Примитив синхронизации CountupEvent - PullRequest
0 голосов
/ 22 апреля 2020

. 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 (как советовал Теодор)?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...