понедельник, 22 августа 2011 г.

Событие с авто-сбросом - это просто глупый семафор

Это перевод An auto-reset event is just a stupid semaphore. Автор: Реймонд Чен.

Когда вы создаёте событие с помощью функции CreateEvent, вы указываете, хотите ли вы создать событие с авто-сбросом (auto-reset event) или с ручным сбросом (manual-reset event).

Событие с ручным сбросом прозрачно для понимания: если событие сброшено, то вы ждёте сигнального состояния; если событие установлено (в сигнальном состоянии), то ожидания не происходит (ожидание удовлетворяется сразу). Не играет значения, сколько человек ждут события; они все обрабатываются одинаково, а состояние события не зависит от числа его ожидающих.

Событие с авто-сбросом - более запутывающая штука.

Вероятно, проще всего думать о событии с авто-сбросом как о семафоре с максимумом счётчика равным единице. Если событие сброшено, то вы ждёте сигнального состояния. Если событие устанавливается, то один из ожидающих будет отпущен, а остальные продолжат ждать (и из нашего обсуждения PulseEvent вы уже знаете, что то, кто именно будет освобождён, - не определено).

"Ага!" в случае событий с авто-сбросом заключается в случае, когда вы устанавливаете уже установленное событие. Поскольку у события есть только два состояния (сброшенное и сигнальное), то установка события, которое и так находится в сигнальном состоянии, не даст никакого эффекта, ничего не изменит. Если вы используете событие, чтобы контролировать ресурс в модели producer/consumer, то "установка уже установленного события" приведёт к потере токена. Рассмотрим такой шаблон:

ProducerConsumer
Ожидание
Задать работу
SetEvent
Проснуться и сбросить событие
Работа
Задать работу
Wait
SetEvent
Проснуться и сбросить событие
Работа
... ...

Но что если тайминг немного не совпадёт? Что если потребитель (consumer) будет медленно делать работу (либо же producer будет слишком быстро её генерировать)?

ProducerConsumer
Ожидание
Задать работу
SetEvent
Проснуться и сбросить событие
Задать работу
SetEvent
Работа
Задать работу
SetEvent (без эффекта)
Ожидание удовлетворено сразу
Сброс события
Работа
Ожидание

Заметьте, что producer создал три задания на работу, но consumer обработал только два. Третий SetEvent просто ничего не сделал, поскольку событие было уже установлено (вы увидите ту же проблему, если попытаетесь увеличить счётчик семафора за его максимум). Если вы хотите, чтобы оба числа соответствовали друг другу, то вам нужно использовать семафор с максимальным значением счётчика выше чем максимум элементов в очереди (прим.пер.: либо же consumer при выходе из ожидания может обрабатывать не один элемент, а все в очереди).

Мораль истории: знайте ваши инструменты, знайте их ограничения и используйте правильный инструмент для правильной задачи.

Комментариев нет:

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.