8

当使用该函数在 libuv 中运行事件循环时uv_run,有一个“mode”参数与以下值一起使用:

UV_RUN_DEFAULT
UV_RUN_ONCE
UV_RUN_NOWAIT

前两个很明显。UV_RUN_DEFAULT运行事件循环,直到没有更多事件,并UV_RUN_ONCE处理循环中的单个事件。但是,UV_RUN_NOWAIT它似乎不是一个单独的模式,而是一个可以与其他两个值之一进行或运算的标志。

默认情况下,此函数会阻塞,直到事件处理完毕,并UV_RUN_NOWAIT使其成为非阻塞,但我能找到的任何文档都到此为止。我的问题是,如果你非阻塞地运行事件循环,回调是如何处理的?

libuv 事件模型是单线程的(反应器模式),所以我假设它需要阻塞才能调用回调,但是如果主线程被占用,事件处理后会发生什么?回调是否会被“排队”直到 libuv 再次控制主线程?还是会在另一个线程上分派回调?

4

1 回答 1

12

回调以相同的方式处理。它们将在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()
    • 没有更多的观察者在循环中运行。例如,唯一的观察者已停止。
    • 它最多处理了一个事件。比如socket接收到数据,调用了用户回调。其他事件可能已准备好处理,但不会在当前uv_run()调用中处理。
  • UV_RUN_NOWAIT如果套接字没有数据,将返回。

通常,以非阻塞方式运行事件循环是为了与其他事件循环集成。考虑一个有两个事件循环的应用程序:用于后端工作的 libuv 和 Qt UI(由它自己的事件循环驱动)。能够以非阻塞方式运行事件循环允许单个线程在两个事件循环上分派事件。这是一个简单的概述,显示了由单个线程处理的两个 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只会运行一次loop1loop1' 的观察者已停止。

有关更多信息,请考虑阅读libuv 简介的高级事件循环进程部分。

于 2013-06-26T20:15:24.650 回答