Pull to refresh

Comments 32

Вопрос. Вы пишете, что правильно не использовать циклы для того, чтобы проверять состояние чего-либо. Вместо этого нужно засыпать и ждать события.

А как устроена прослушивание события внутри? Разве там не такой-же цикл? Мне кажется, что единственный способ остановить алгоритм, при этом не завершив его — это зацикливание.
monitor/mwait еще позволяет заснуть до наступления события. В юзермоде недоступно пока, к сожалению.
Так мне и интересно, как устроен код, который проксирует событие в пользовательский код.
WaitForSingleObject(wsaSocketEvent, INFINITE); — вот эта функция как устроена?
Вероятно, эта функция общается с драйвером, а драйвер обрабатывает аппаратные прерывания. В этом случае никакой цикл с поллингом не нужен
Во, спасибо! А то минусы-минусы.
> А кто эти прерывания генерировать будет? Тоже программы ведь.
Неа, их генерируют устройства, потому они и назваются аппаратными.

Процессор умеет останавливать свою работу, для этого существует специальная команда. Для х86 это HLT. Вывести его из остановленного состояния как раз может аппаратное прерывание
Я имел в виду то, что устройство без программы — простая железка, а вот та программа, которая на них выполняется, как раз и заставляет их генерировать прерывания, передавая их другим компонентам (сетевая карта слушает порт, и если она «услышит» сигнал, она разбудит ЦП, который обработает поступивший пакет, и «забудит» обратно).
Вполне может быть, что она приостанавливает вызывающий поток до поступления события.
Отдает управление обратно ОС, выставляется флаг мол ждет события. Ну а дальше переключается TSS на следующую задачу. Через некоторое время опять приходит черед этому процессу, проверяется есть это событие или нет, если да то продолжает выполняться, если нет то процессорное время отдается следующему. Если все ждут то работает while(1) {hlt} останавливающий проц до срабатывания следующего прерывания
Проблема не в цикле,
WaitForSingleObject(wsaSocketEvent, INFINITE);
Вернет управление когда случится событие,
а recv(serverSocket, buffer, bufferLen, 0);
примет 0 байт если ничего не пришло
Проблема в том, что с использованием Sleep код будет производить периодическую, ненужную активность.
Присоединяюсь. Есть ли hardware-поддержка Event-Driven программ, или же события таки эмулируются опросом «Уже приехали? А теперь приехали?» на самом-самом-самом низком уровне?
Да, если это аппаратные прерывания (и если я правильно представляю, как оно может работать без такой же постоянно слушающей программы, пусть и низкоуровневой)…

Так, стоп. А кто эти прерывания генерировать будет? Тоже программы ведь. Если не программы, значит, обработку нужно выносить на внешнее устройство, чтобы процессор вообще не был занят (ни пользовательскими программами, ни ОС, ни низкоуровневыми вещами) и, соотвественно, мог останавливать свою работу. А внешнее устройство также требует источник питания. Может, я чего-то не понимаю, но полностью уйти от постоянно работающих программ не получится (банально — генерация сигнала от видеокарты на монитор (видеокарта — тоже компьютер со своим процессором, памятью etc, и кто скажет, что это не так, пусть первый кинет в меня камень)), но можно снизить количество мучающих процессор задач путем сведения всех «опросников состояния» к более-менее единой системе (таймер ОС, аппаратные прерывания). Автор, ты это хотел сказать?
Допустим у нас сетевой сервис, например, веб-сервер. Запросов нет, обрабатывать нечего, процессор уходит в «спячку» при вызове WaitForSingleObject(). Приходит пакет на сетевую карту, она генерирует аппаратное прерывание, процессор просыпается, получает от нее данные, возвращает управление в WaitForSingleObject(), в основном цикле программы запрос обрабатывается, опять вызывается WaitForSingleObject() и процессор опять засыпает до следующего пакета.

Сетевая карта при таком раскладе, конечно, должна работать, но потребляет она гораздо меньше процессора, который бы её постоянно опрашивал. То же и с видеокартой, причем есть подозрения :), что при выводе статической картинки потребление энергии минимально и вмешательства основного процессора не требуется.
Все это уходит очень глубоко в подсистему windows kernel, где задействуется в том числе и планировщик потоков, который не выделяет процессорного времени потоку, «висящему» на объекте синхронизации.

Была какая-то хорошая книжка по архитектуре Windows 2000, там это описывалось.
Интересно, но хотелось бы немного информации о unix like для сравнения с windows api…
И там и там одинаково хорошо.
Это у автора надо спросить, зачем создавать видимость, что recv плохо, а WSAEventSelect — хорошо.
Я написал выше, что не recv плохо, а плохо создавать ненужную активность. В примере выше WSAEventSelect по сути не играет никакой роли, акцент был сделан на WaitForSingleObject :)
Значит название раздела «События рулят или Event-driven подход» выбрано не совсем удачно.
Ну почему не сделать акцент на тот же select()? Стандартная функция из BSD sockets. Поддерживается в том числе и в WinSockets. Все примеры были бы унифицированны.
Понял свою ошибку, для чистоты сравнения обоих подходов стоило использовать просто recv после WaitForSingleObject
Ну я вообще намекал, что вместо WaitForSingleObject можно select() использовать :)
Или вообще вызвать recv() в блокирующем режиме.
С точки зрения энергоэфективности одинаково хорошо как event-driven в одном потоке, так и блокирующие вызовы в отдельных потоках.

Переход от recv (которая может работать в блокирующем режиме) к WSAEventSelect (event driven) вносит лишнюю путаницу. Event-driven с экономией на количестве потоков часто имеет смысл, но к теме этой статьи отношения не имеет.
Да, есть такой инструмент. Если честно то сам ни разу не пользовался, и боюсь писать о том, чего не знаю. :)
Так он же под линукс, а тут про винду вроде речь.
Дошел до этого момента и чуть не стошнило
BOOL WINAPI<br/> SetWaitableTimerEx(<br/> __in HANDLE hTimer,<br/> __in const LARGE_INTEGER *lpDueTime,<br/> __in LONG lPeriod,<br/> __in_opt PTIMERAPCROUTINE pfnCompletionRoutine,<br/> __in_opt LPVOID lpArgToCompletionRoutine,<br/> __in_opt PREASON_CONTEXT WakeContext,<br/> __in ULONG TolerableDelay<br/> );<br/>
Функция с 7 параметрами, куча тайпдефов, не удивлюсь что там еще и маленькая кучка структур (с кучей своей пое..), каждый параметр нужно смотреть в документации что он значит и из чего состоит. Какой ппц, вы уж меня извините за грубость.
Простите, вы разработчик или где?
p.s: и функция эта вызывается один раз только при установке таймера ;) код работы с уже имеющимся в программе таймером менять не придётся.
Было познавательно, спасибо. Думаю логическим продолжением будет подобная статья о архитектуре APM, как там работает вся эта кухня, и за счет чего их получилось сделать менее энергоемкими.
Only those users with full accounts are able to leave comments. Log in, please.