所以我刚刚发现,就C库而言,libuv是一个相当小的库(与FFmpeg相比)。我花了6个小时来阅读源代码,以更深入地了解事件循环。但是仍然看不到实现“非阻塞性”的地方。在代码库中正在调用某些事件中断信号或其他事件的地方。
我已经使用Node.js八年了,所以我熟悉如何使用异步非阻塞事件循环,但是我从未真正研究过实现。
我的问题是双重的:
因此,我们从一个Hello World示例开始。所需的只是这个:
#include <stdio.h>
#include <stdlib.h>
#include <uv.h>
int main() {
uv_loop_t *loop = malloc(sizeof(uv_loop_t));
uv_loop_init(loop); // initialize datastructures.
uv_run(loop, UV_RUN_DEFAULT); // infinite loop as long as queue is full?
uv_loop_close(loop);
free(loop);
return 0;
}
我一直在探索的关键功能是uv_run
。 uv_loop_init
函数本质上是初始化数据结构,所以我认为那里没有太多幻想。但是,真正的魔力似乎发生在uv_run
,somewhere上。 libuv存储库中的高级代码段集为in this gist,显示了uv_run
函数调用的内容。
本质上似乎可以归结为:
while (NOT_STOPPED) {
uv__update_time(loop)
uv__run_timers(loop)
uv__run_pending(loop)
uv__run_idle(loop)
uv__run_prepare(loop)
uv__io_poll(loop, timeout)
uv__run_check(loop)
uv__run_closing_handles(loop)
// ... cleanup
}
这些功能很重要。
uv__run_timers
:运行计时器回调吗? for (;;) {
循环。uv__run_pending
:运行常规回调? while (!QUEUE_EMPTY(&pq)) {
在队列中循环。uv__run_idle
:无源代码uv__run_prepare
:无源代码uv__io_poll
:io轮询吗? (还不太清楚这是什么意思)。有2个循环:while (!QUEUE_EMPTY(&loop->watcher_queue)) {
和for (;;) {
,然后我们完成了。该程序存在,因为没有“工作”要做。
因此,我认为在完成所有这些挖掘之后,我已经回答了问题的第一部分,并且循环特别是在这三个函数中:
uv__run_timers
uv__run_pending
uv__io_poll
但是没有用kqueue
或多线程实现任何东西,并且对文件描述符的处理相对较少,我不太遵循代码。这也可能会帮助其他人学习此方法。
所以问题的第二部分是这三个实现非阻塞性的函数中的关键步骤是什么?假设这是所有循环都存在的地方。
不是C语言专家,for (;;) {
是否“阻止”事件循环?还是可以无限期运行,并以某种方式将代码的其他部分从OS系统事件或类似事件中跳转到?]
因此uv__io_poll
在该无限循环中调用poll(...)
。我不认为这是正确的吗?这似乎就是它主要要做的。
[查看kqueue.c
也有一个uv__io_poll
,所以我假设poll
实现是一个后备,并且在Mac上使用了kqueue
,这是非阻塞的?
是这样吗?它是否只是循环进入uv__io_poll
,并且您可以将每个迭代添加到队列中,并且只要队列中有内容,它就会运行?我仍然看不到它是如何非阻塞和异步的。
一个轮廓可以与此类似吗,它是异步和非阻塞的,需要看代码的哪一部分?基本上,我想了解libuv中“空闲处理器空闲”的位置。呼叫我们的初始uv_run
的处理器在哪里空闲?如果它是免费的,它如何像事件处理程序一样被重新调用? (就像来自鼠标的浏览器事件处理程序一样,是一个中断)。我觉得我正在寻找中断,但没有看到中断。
我问这个问题是因为我想在C语言中实现MVP事件循环,但只是不了解如何实际实现非阻塞性。橡胶与路的交汇处。
因此,我刚刚发现libuv就C库而言是一个很小的库(与FFmpeg相比)。在过去的6个小时中,我通读了源代码,以了解这次活动...
[我只是深入研究libuv
的源代码,起初发现它似乎做了很多设置,而没有太多实际事件处理。