Как работает режим 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".

Другие вопросы по тегам