. NET содержит CountdownEvent
.
CountdownEvent
представляет примитив синхронизации, который сигнализируется, когда его счет достигает нуля.
Мне нужен счетчик up Событие (обратное CountdownEvent
), чтобы он сигнализировался, когда его счет больше нуля, и не сигнализировался, когда его счет равнялся нулю.
Конечно, API нужно адаптировать. Например, метод TryAddCount
может превратиться в метод TryReduceCount
. Возможно, требуется более радикальное изменение API. Возможно API с запрошенным поведением невозможен (хотя я в этом сомневаюсь). Возможно, получить ответы на эти вопросы возможно только путем реализации запрошенного поведения. Нужны любые мысли, связанные с API, или готовая реализация.
Я занимаюсь разработкой асинхронного процессора задач. Есть поток, который спит, когда нет задач (CountupEvent.Count == 0
), и просыпается, когда появляются задачи (CountupEvent.Count > 0
). Как только задача завершена, CountupEvent.Count
уменьшается на 1. Как только появляется новая задача, CountupEvent.Count
увеличивается на 1. Обработка задач и добавление задач могут выполняться в разных потоках. Если есть готовая реализация или концепция CountupEvent
, я могу настроить поведение своего процессора в соответствии с ней. Любые мысли будут полезны.
Я пытался реализовать с AutoResetEvent
, но у него есть условие гонки:
public class Processor
{
ConcurrentQueue<Action> _workItemQueue = new ConcurrentQueue<Action>();
AutoResetEvent _newWorkItemAutoResetEvent = new AutoResetEvent(false);
private bool _disposed;
Thread _thread;
public void Do(Action action)
{
_workItemQueue.Enqueue(action);
_newWorkItemAutoResetEvent.Set();
}
public Processor()
{
_workerThread = new Thread(() =>
{
while (!_disposed)
{
_newWorkItemAutoResetEvent.WaitOne(); //
while (_workItemQueue.TryDequeue(out Action action))
{
action();
}
// at this "bad" moment another thread calls Do method.
// New action has been enqueued, but when we call
// _newWorkIteManualAutoEvent.WaitOne() we fall asleep.
}
});
_thread.Start();
}
}
Затем я попробовал реализацию с ManualResetEvent
:
public class Processor
{
ConcurrentQueue<Action> _workItemQueue = new ConcurrentQueue<Action>();
ManualResetEvent _newWorkItemManualResetEvent = new ManualResetEvent(false);
private bool _disposed;
Thread _thread;
public void Do(Action action)
{
_workItemQueue.Enqueue(action);
_newWorkItemManualResetEvent.Set();
}
public Processor()
{
_workerThread = new Thread(() =>
{
while (!_disposed)
{
_newWorkItemManualResetEvent.WaitOne();
_newWorkItemManualResetEvent.Reset();
while (_workItemQueue.TryDequeue(out Action action))
{
action();
}
}
});
_thread.Start();
}
}
Я не вижу условий гонки в реализации с ManualResetEvent
.
ВОПРОС: Я прав? Или мне все еще нужен дополнительный примитив синхронизации, например Count up Event или мне нужно BlockingCollection
(как советовал Теодор)?