Windows Service - разрешить не более одного вызова
От: Аноним  
Дата: 10.01.14 04:33
Оценка:
У нас есть некий Windows Service (Service1)
Надо сделать так, чтобы пользователи или процессы не могли ОДНОВРЕМЕННО вызывать методы Service1.
Вызовы делаются через remoting

Т.е. если кто-то вызвал метод и он в процесе отработки, то след вызов возможен только тогда когда первый вызов прекратит работу

Вопрос: как это реалиховать, правильно ли это реализорвано ниже — в классе сервиса есть счетчик вызова или флаг

Спасибо

//Service
class MyService : MarshalByRefObject, IMyService
{

private bool bWorking = false;

public void MyMethod()
{

if(bWorking)
   throw new Exception("Метод уже вызван. Подождите.");

bWorking = true;

DoMainWork();

bWorking = false;

}

}


//..............


//Client

TcpChannel channel = new TcpChannel();
ChannelService.RegisterChannel(channel, false);
IMyService srv = (IMyService)Activator.GetObject(typeof(IMyService), url);
srv.MyMethod();
ChannelService.UnRegisterChannel(channel);
Re: Windows Service - разрешить не более одного вызова
От: маген Россия https://ru.linkedin.com/pub/alexey-smorkalov/4/283/8b8
Дата: 10.01.14 04:45
Оценка:
А>Вопрос: как это реалиховать, правильно ли это реализорвано ниже — в классе сервиса есть счетчик вызова или флаг

Не правильно.

Читайте про Threading, в частности про синхронизацию

По постановке вопроса вам надо курить
lock
Re[2]: Windows Service - разрешить не более одного вызова
От: Философ Ад http://vk.com/id10256428
Дата: 10.01.14 04:54
Оценка:
Здравствуйте, маген, Вы писали:

М>По постановке вопроса вам надо курить
lock


NetRemoting разве не каждый раз создаёт объект перед тем как дёрнуть его метод (я не помню)?
Если каждый раз, то синхронизация здесь не нужна.
Всё сказанное выше — личное мнение, если не указано обратное.
Re[3]: Windows Service - разрешить не более одного вызова
От: маген Россия https://ru.linkedin.com/pub/alexey-smorkalov/4/283/8b8
Дата: 10.01.14 05:04
Оценка:
Здравствуйте, Философ, Вы писали:

Ф>Здравствуйте, маген, Вы писали:


М>>По постановке вопроса вам надо курить
lock


Ф>NetRemoting разве не каждый раз создаёт объект перед тем как дёрнуть его метод (я не помню)?

Ф>Если каждый раз, то синхронизация здесь не нужна.

1. Почему вы решили, что не нужна? Топикстартер тогда о чем пишет? Мы же не знаем к каким ресурсам идет обращение.
Ну и может просто каприз постановщика что вот этот метод не работает одновременно для разных клиентов, почему нет

2. Тогда какой смысл по-вашему в решении топикстартера, при каких условиях может сработать эта переменная?
Re[4]: Windows Service - разрешить не более одного вызова
От: Философ Ад http://vk.com/id10256428
Дата: 10.01.14 05:17
Оценка:
Здравствуйте, маген, Вы писали:

М>Здравствуйте, Философ, Вы писали:


Ф>>Здравствуйте, маген, Вы писали:


М>>>По постановке вопроса вам надо курить
lock


Ф>>NetRemoting разве не каждый раз создаёт объект перед тем как дёрнуть его метод (я не помню)?

Ф>>Если каждый раз, то синхронизация здесь не нужна.

М>1. Почему вы решили, что не нужна? Топикстартер тогда о чем пишет? Мы же не знаем к каким ресурсам идет обращение.


Вот эти ресурсы и нужно синхронизировать.
Мне почему-то в голову запало то, что для класса, экземпляры которого маршалятся ремотингом как реф обжект ( базовый класс MarshalByRefObject),
ремотингом создаются свои экземпляры для каждого клиента, и при этом вызов идёт последовательно.
Т.е. пока ремотинг не делает многопоточные вызовы. Следовательно многопоточного обращения к bWorking не будет.
Синхронизация нужна не здесь.


Однако я могу ошибаться — NetRemoting не видел давненько.


М>Ну и может просто каприз постановщика что вот этот метод не работает одновременно для разных клиентов, почему нет


М>2. Тогда какой смысл по-вашему в решении топикстартера, при каких условиях может сработать эта переменная?


Однако приходится признать, что тут я не прав.
Всё сказанное выше — личное мнение, если не указано обратное.
Re: Windows Service - разрешить не более одного вызова
От: Философ Ад http://vk.com/id10256428
Дата: 10.01.14 05:28
Оценка:
Вместо инстансного булевского поля bWorking здесь лучше использовать ManualResetEvent

примерно вот так:


class MyService : MarshalByRefObject, IMyService
{
private static ManualResetEvent MyMethodWorkingEvent;
public static MyService()
{
  MyMethodWorkingEvent = new ManualResetEvent(true)
}

public void MyMethod()
{
  if (!MyMethodWorkingEvent.WaitOne(0))
    throw new Exception("Метод уже вызван. Подождите.");
    MyMethodWorkingEvent.Reset();

/*

 здесь идёт тело метода

*/

MyMethodWorkingEvent.Set();
}
Всё сказанное выше — личное мнение, если не указано обратное.
Re[5]: Windows Service - разрешить не более одного вызова
От: маген Россия https://ru.linkedin.com/pub/alexey-smorkalov/4/283/8b8
Дата: 10.01.14 05:48
Оценка:
Ф>Мне почему-то в голову запало то, что для класса, экземпляры которого маршалятся ремотингом как реф обжект ( базовый класс MarshalByRefObject),
Ф>ремотингом создаются свои экземпляры для каждого клиента, и при этом вызов идёт последовательно.
Ф>Т.е. пока ремотинг не делает многопоточные вызовы. Следовательно многопоточного обращения к bWorking не будет.
Ф>Синхронизация нужна не здесь.

Ф>Однако я могу ошибаться — NetRemoting не видел давненько.


Проверить просто:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

namespace TestMarshal
{

    public class Worker : MarshalByRefObject
    {
        public void Print()
        {
            Console.WriteLine(string.Format("PrintDomain enter {0}", Thread.CurrentThread.ManagedThreadId));
            Thread.Sleep(1000);
            Console.WriteLine(string.Format("PrintDomain exit {0}", Thread.CurrentThread.ManagedThreadId));
        }
    }

    class Program
    {
        static void CallWorker(int id)
        {
            AppDomain ad = AppDomain.CreateDomain(string.Format("domain{0}", id));
            Worker remoteWorker = (Worker)ad.CreateInstanceAndUnwrap(
                Assembly.GetExecutingAssembly().FullName,
                "TestMarshal.Worker");
            remoteWorker.Print();
        }

        public static void Main()
        {
            for (int i = 0; i < 3; i++)
            {
                Task.Factory.StartNew(() => CallWorker(i));
            }
            Console.ReadKey();
        }
    }
}


Вывод

PrintDomain enter 10
PrintDomain enter 11
PrintDomain enter 14
PrintDomain exit 10
PrintDomain exit 11
PrintDomain exit 14

Re[6]: Windows Service - разрешить не более одного вызова
От: маген Россия https://ru.linkedin.com/pub/alexey-smorkalov/4/283/8b8
Дата: 10.01.14 06:08
Оценка:
Здравствуйте, маген, Вы писали:


Ф>>Мне почему-то в голову запало то, что для класса, экземпляры которого маршалятся ремотингом как реф обжект ( базовый класс MarshalByRefObject),

Ф>>ремотингом создаются свои экземпляры для каждого клиента, и при этом вызов идёт последовательно.
Ф>>Т.е. пока ремотинг не делает многопоточные вызовы. Следовательно многопоточного обращения к bWorking не будет.
Ф>>Синхронизация нужна не здесь.

Ф>>Однако я могу ошибаться — NetRemoting не видел давненько.


М>Проверить просто:


Извиняюсь, не совсем корректный пример был — каждый вызов в разном домене приложения,
но и в пределах одного результат тот же.

Для протокола

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;

namespace TestMarshal
{

    public class Worker : MarshalByRefObject
    {
        static object _lock = new object();
        public void Print()
        {
            //lock (_lock)
            {
                Console.WriteLine(string.Format("PrintDomain enter {0}", Thread.CurrentThread.ManagedThreadId));
                Thread.Sleep(1000);
                Console.WriteLine(string.Format("PrintDomain exit {0}", Thread.CurrentThread.ManagedThreadId));
            }
        }
    }

    class Program
    {
        static void CallWorker(AppDomain ad, int id)
        {
            Worker remoteWorker = (Worker)ad.CreateInstanceAndUnwrap(
                Assembly.GetExecutingAssembly().FullName,
                "TestMarshal.Worker");
            remoteWorker.Print();
        }

        public static void Main()
        {
            AppDomain ad = AppDomain.CreateDomain(string.Format("domain"));
            for (int i = 0; i < 3; i++)
            {
                Task.Factory.StartNew(() => CallWorker(ad, i));
            }
            Console.ReadKey();
        }
    }
}


Топикстартеру решение — раскомментировать lock.
Re: Windows Service - разрешить не более одного вызова
От: Partner  
Дата: 10.01.14 07:59
Оценка:
Здравствуйте, Аноним, Вы писали:

А>У нас есть некий Windows Service (Service1)

А>Надо сделать так, чтобы пользователи или процессы не могли ОДНОВРЕМЕННО вызывать методы Service1.
А>Вызовы делаются через remoting

А>Т.е. если кто-то вызвал метод и он в процесе отработки, то след вызов возможен только тогда когда первый вызов прекратит работу


А>Вопрос: как это реалиховать, правильно ли это реализорвано ниже — в классе сервиса есть счетчик вызова или флаг



Заверните свои методы в STA COM объект и никакой синхронизации не потребуется.
Все вызовы методов будут сериализированы автоматически, под капотом COM'а.
Re: Windows Service - разрешить не более одного вызова
От: TK Лес кывт.рф
Дата: 10.01.14 09:55
Оценка: 1 (1) +1
Здравствуйте, Аноним, Вы писали:

А>У нас есть некий Windows Service (Service1)

А>Надо сделать так, чтобы пользователи или процессы не могли ОДНОВРЕМЕННО вызывать методы Service1.
А>Вызовы делаются через remoting

А>Т.е. если кто-то вызвал метод и он в процесе отработки, то след вызов возможен только тогда когда первый вызов прекратит работу


А>Вопрос: как это реалиховать, правильно ли это реализорвано ниже — в классе сервиса есть счетчик вызова или флаг


Наследуйтесь от ContextBoundObject с которым можно использовать SynchronizationAttribute
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[2]: Windows Service - разрешить не более одного вызова
От: Pavel Dvorkin Россия  
Дата: 10.01.14 10:15
Оценка:
Здравствуйте, Философ, Вы писали:

Ф>Вместо инстансного булевского поля bWorking здесь лучше использовать ManualResetEvent


Вообще-то для взаимоисключения обычно применяют Mutex
With best regards
Pavel Dvorkin
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.