Предположим, я обрабатываю большое количество входящих данных из нескольких потоков. Я могу захотеть, чтобы эти данные выступали в качестве триггера для конкретного действия при соблюдении определенных критериев. Тем не менее, действие не реентерабельное; таким образом, один и тот же триггер, запускаемый дважды в быстрой последовательности, должен запускать действие только один раз.
Использование простого флага bool
для указания того, выполняется ли текущее действие, не является надежным решением, поскольку может возникнуть условие гонки, и два (или более) потока могут все же в конечном итоге выполнить одно и то же действие одновременно. Конечно, сработает bool
в операторе lock
объекта синхронизации; но я обычно предпочитаю избегать блокировок, когда это возможно *.
В настоящее время в этих случаях я использую AutoResetEvent
, по сути, как атомный переключатель. Код обычно выглядит примерно так:
if (conditionMet && readyForAction.WaitOne(0))
{
try
{
doAction();
}
finally
{
readyForAction.Set();
}
}
Это работает, но мне кажется, что это может быть далеко не идеальный вариант использования для класса AutoResetEvent
. Вы сказали бы, что это подходящее решение этой проблемы, или было бы более разумно использовать какой-то другой механизм?
Обновление : Как и Джон указал , используя Monitor.TryEnter
в качестве стратегии блокировки (вместо простого lock
, который, я считаю, примерно эквивалентен Monitor.Enter
) , действительно довольно просто:
if (conditionMet && Monitor.TryEnter(lockObject))
{
try
{
doAction();
}
finally
{
Monitor.Exit(lockObject);
}
}
Тем не менее, я сильно склонен согласиться с Хенком об использовании Interlocked
. Кажется, все так просто.