Windows Service - разрешить не более одного вызова
От:
Аноним
Дата:
10.01.14 04:33
Оценка:
У нас есть некий Windows Service (Service1)
Надо сделать так, чтобы пользователи или процессы не могли ОДНОВРЕМЕННО вызывать методы Service1.
Вызовы делаются через remoting
Т.е. если кто-то вызвал метод и он в процесе отработки, то след вызов возможен только тогда когда первый вызов прекратит работу
Вопрос: как это реалиховать, правильно ли это реализорвано ниже — в классе сервиса есть счетчик вызова или флаг
Здравствуйте, Философ, Вы писали:
Ф>Здравствуйте, маген, Вы писали:
М>>По постановке вопроса вам надо курить
lock
Ф>NetRemoting разве не каждый раз создаёт объект перед тем как дёрнуть его метод (я не помню)? Ф>Если каждый раз, то синхронизация здесь не нужна.
1. Почему вы решили, что не нужна? Топикстартер тогда о чем пишет? Мы же не знаем к каким ресурсам идет обращение.
Ну и может просто каприз постановщика что вот этот метод не работает одновременно для разных клиентов, почему нет
2. Тогда какой смысл по-вашему в решении топикстартера, при каких условиях может сработать эта переменная?
Re[4]: Windows Service - разрешить не более одного вызова
Здравствуйте, маген, Вы писали:
М>Здравствуйте, Философ, Вы писали:
Ф>>Здравствуйте, маген, Вы писали:
М>>>По постановке вопроса вам надо курить
lock
Ф>>NetRemoting разве не каждый раз создаёт объект перед тем как дёрнуть его метод (я не помню)? Ф>>Если каждый раз, то синхронизация здесь не нужна.
М>1. Почему вы решили, что не нужна? Топикстартер тогда о чем пишет? Мы же не знаем к каким ресурсам идет обращение.
Вот эти ресурсы и нужно синхронизировать.
Мне почему-то в голову запало то, что для класса, экземпляры которого маршалятся ремотингом как реф обжект ( базовый класс MarshalByRefObject),
ремотингом создаются свои экземпляры для каждого клиента, и при этом вызов идёт последовательно.
Т.е. пока ремотинг не делает многопоточные вызовы. Следовательно многопоточного обращения к bWorking не будет.
Синхронизация нужна не здесь.
Однако я могу ошибаться — NetRemoting не видел давненько.
М>Ну и может просто каприз постановщика что вот этот метод не работает одновременно для разных клиентов, почему нет
М>2. Тогда какой смысл по-вашему в решении топикстартера, при каких условиях может сработать эта переменная?
Однако приходится признать, что тут я не прав.
Всё сказанное выше — личное мнение, если не указано обратное.
Re: Windows Service - разрешить не более одного вызова
Вместо инстансного булевского поля 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 - разрешить не более одного вызова
Ф>Мне почему-то в голову запало то, что для класса, экземпляры которого маршалятся ремотингом как реф обжект ( базовый класс 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 - разрешить не более одного вызова
Ф>>Мне почему-то в голову запало то, что для класса, экземпляры которого маршалятся ремотингом как реф обжект ( базовый класс 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 - разрешить не более одного вызова
Здравствуйте, Аноним, Вы писали:
А>У нас есть некий Windows Service (Service1) А>Надо сделать так, чтобы пользователи или процессы не могли ОДНОВРЕМЕННО вызывать методы Service1. А>Вызовы делаются через remoting
А>Т.е. если кто-то вызвал метод и он в процесе отработки, то след вызов возможен только тогда когда первый вызов прекратит работу
А>Вопрос: как это реалиховать, правильно ли это реализорвано ниже — в классе сервиса есть счетчик вызова или флаг
Заверните свои методы в STA COM объект и никакой синхронизации не потребуется.
Все вызовы методов будут сериализированы автоматически, под капотом COM'а.
Re: Windows Service - разрешить не более одного вызова
Здравствуйте, Аноним, Вы писали:
А>У нас есть некий Windows Service (Service1) А>Надо сделать так, чтобы пользователи или процессы не могли ОДНОВРЕМЕННО вызывать методы Service1. А>Вызовы делаются через remoting
А>Т.е. если кто-то вызвал метод и он в процесе отработки, то след вызов возможен только тогда когда первый вызов прекратит работу
А>Вопрос: как это реалиховать, правильно ли это реализорвано ниже — в классе сервиса есть счетчик вызова или флаг
Наследуйтесь от ContextBoundObject с которым можно использовать SynchronizationAttribute
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[2]: Windows Service - разрешить не более одного вызова