Использование дескриптора ожидания

Я пытаюсь сделать что-то вроде этого:

EventWaitHandle handler = new EventWaitHandle(false, EventResetMode.AutoReset)

//This code will run in background thread
private void AsyncWait() {
    while (true) {
        handler.WaitOne();
        //LongRunningOperation()
    }
}

В другом месте кода будут методы, которые вызывают:

handler.Set()

Итак, выполняется LongRunningOperation().

Проблема в том, что handler.Set() можно вызвать снова, пока поток AsyncWait() выполняет LongRunningOperation().

Это означает, что LongRunningOperation() никогда не будет вызываться всякий раз, когда вызывается handler.Set(), пока AsyncWait() все еще выполняет LongRunningOperation().

Как сделать это правильно? :(


person ch0eb1t    schedule 06.11.2013    source источник
comment
Если вы вызвали handler.Set(), handler.Set(), handler.WaitOne(), handler.WaitOne(), хотите ли вы, чтобы последний WaitOne() не блокировался, потому что Set уже вызывался дважды?   -  person Scott Chamberlain    schedule 06.11.2013
comment
@ Скотт Чемберлен, точно   -  person ch0eb1t    schedule 06.11.2013
comment
Вы используете EventResetMode.AutoReset, поэтому, даже когда LongRunningOperation() работает, handler уже был (автоматически) сброшен, поэтому, когда вы вызываете handler.Set() во время LongRunningOperation(), это не приведет к блокировке следующего handler.WaitOne();, поскольку он уже был сброшен сразу после его ожидания. Так что либо проблемы нет, либо я думаю, что не вижу ясно вашей проблемы...   -  person Stormenet    schedule 06.11.2013
comment
@Stormenet Нет, следующий обработчик.WaitOne() заблокируется.   -  person ch0eb1t    schedule 06.11.2013
comment
Этого не должно быть, см. следующий пример (создайте стандартный проект Windows Forms и замените код Form1): pastebin.com/bCqYdpSm У меня выводит Pass: 1 Pass: 2   -  person Stormenet    schedule 06.11.2013


Ответы (1)


Используйте семафор вместо AutoResetEvent.

Семафор использует внутренний счетчик. Вы также можете определить максимальное количество потоков, которые могут быть «пропущены» одновременно.

readonly Semaphore _semaphore = new Semaphore(0, int.MaxValue);

public void Enqueue<T>(T item)
{
     _internalQueue.Enqueue(item);
     _semaphore.Release();  // Informs that deque task to unblock if waiting. Equivalent to the  WaitHandle.Set() method. Increases the semaphore counter
}

public T Dequeue()
{
     _semaphore.WaitOne();   // Blocks as long as there are no items in the queue. Decreases the semaphore counter when "let through". Blocks the thread as long as semaphore counter is zero.
     return _internalQueue.Dequeue();
}
person Frode    schedule 06.11.2013
comment
Чувствуется решение. Мне нужно пройти больше тестов, чтобы проверить и установить это как ответ. - person ch0eb1t; 06.11.2013
comment
@ch0eb1t Он ведет себя точно так же, как в примере, который я разместил в комментариях к вашему вопросу. - person Scott Chamberlain; 06.11.2013