libuv中的UV_RUN_NOWAIT模式是如何工作的?

8
在使用uv_run函数运行libuv中的事件循环时,有一个“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个回答

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()明确停止。 - 循环中没有更多的观察器运行。例如,唯一的观察器已停止。 - 它处理了最多一个事件。例如,套接字接收到数据,并调用了用户回调函数。可能有其他事件准备好处理,但在当前的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_NOWAITloop2 只有在停止 loop1 或者 loop1 的观察者后才会运行一次。

如需更多信息,请阅读高级事件循环进程部分的libuv简介


2
那份文档(在uv.h中的那个)已经过时,有时也不准确。新的文档在docs.libuv.org上:http://docs.libuv.org/en/v1.x/loop.html#c.uv_run - saghul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接