Как работает режим UV_RUN_NOWAIT в libuv?
При запуске цикла событий в libuv с использованием uv_run
функция, есть параметр "mode", который используется со следующими значениями:
UV_RUN_DEFAULT
UV_RUN_ONCE
UV_RUN_NOWAIT
Первые два очевидны. UV_RUN_DEFAULT
запускает цикл обработки событий, пока больше нет событий, и UV_RUN_ONCE
обработка одного события из цикла. Тем не мение, UV_RUN_NOWAIT
похоже, это не отдельный режим, а флаг, который может быть установлен OR с одним из двух других значений.
По умолчанию эта функция блокируется до завершения обработки событий, и UV_RUN_NOWAIT
делает его неблокирующим, но любая документация, которую я могу найти на этом, заканчивается там. Мой вопрос: если вы запускаете неблокирование цикла событий, как обрабатываются обратные вызовы?
Модель событий libuv является однопоточной (модель реактора), поэтому я предполагаю, что для того, чтобы иметь возможность вызывать обратные вызовы, она должна блокироваться, но если основной поток занят, что происходит с событием после его обработки? Будет ли обратный вызов "поставлен в очередь", пока libuv снова не получит контроль над основным потоком? Или обратные вызовы будут отправлены в другой поток?
1 ответ
Обратные вызовы обрабатываются таким же образом. Они будут работать в потоке, который находится в uv_run()
,
Согласно документации:
UV_RUN_DEFAULT
: Запускает цикл обработки событий, пока счетчик ссылок не упадет до нуля. Всегда возвращает ноль.UV_RUN_ONCE
: Опрос для новых событий один раз. Обратите внимание, что эта функция блокируется, если нет ожидающих событий. Возвращает ноль, когда выполнено (нет активных дескрипторов или запросов не осталось), или ненулевое, если ожидается больше событий (что означает, что вы должны снова запустить цикл обработки событий в будущем).UV_RUN_NOWAIT
: Опрашивать новые события один раз, но не блокировать, если нет ожидающих событий.
Рассмотрим случай, когда программа имеет одного наблюдателя, слушающего сокет. В этом случае событие будет создано, когда сокет получит данные.
UV_RUN_DEFAULT
заблокирует звонящего, даже если сокет не имеет данных. Звонящий вернется изuv_run()
когда либо:- Цикл был явно остановлен через
uv_stop()
- Больше нет наблюдателей в цикле. Например, единственный наблюдатель был остановлен.
- Цикл был явно остановлен через
UV_RUN_ONCE
заблокирует звонящего, даже если сокет не имеет данных. Звонящий вернется изuv_run()
когда происходит любое из следующего:- Цикл был явно остановлен через
uv_stop()
- Больше нет наблюдателей в цикле. Например, единственный наблюдатель был остановлен.
- Он обработал максимум одно событие. Например, сокет получил данные, и был вызван обратный вызов пользователя. Дополнительные события могут быть готовы к обработке, но не будут обработаны в текущем
uv_run()
вызов.
- Цикл был явно остановлен через
UV_RUN_NOWAIT
вернется, если сокет не имеет данных.
Часто запуск цикла событий неблокирующим образом выполняется для интеграции с другими циклами событий. Рассмотрим приложение, которое имеет два цикла событий: libuv для работы с бэкэндом и пользовательский интерфейс Qt (который управляется собственным циклом событий). Возможность запуска цикла событий неблокирующим образом позволяет одному потоку отправлять события в оба цикла событий. Вот упрощенный обзор, показывающий, что два цикла libuv обрабатываются одним потоком:
uv_loop_t *loop1 = uv_loop_new();
uv_loop_t *loop2 = uv_loop_new();
// create, initialize, and start a watcher for each loop.
...
// Handle two event loops with a single thread.
while (uv_run(loop1, UV_RUN_NOWAIT) || uv_run(loop2, UV_RUN_NOWAIT));
Без использования UV_RUN_NOWAIT
, loop2
будет работать только один раз loop1
или же loop1
наблюдатели были остановлены.
Для получения дополнительной информации рассмотрите разделы " Расширенные циклы событий и процессы" в разделе "Введение в libuv".