简单的定时器事件循环
Simple timer event loop
用例
我正在编写一个需要多个计时器的 C 程序。我首先编写了一个快速原型,它为每个计时器启动了一个 pthread
。只是一个带有 sleep
命令的简单 while
循环,因为 1 秒分辨率就足够了。
但是如果有 10 个以上的定时器,它的效率就不是很高,也不是生产级的代码质量。因此我想使用事件循环。我已经多次阅读有关 libuv 的文章,并想尝试一下。
所以我的想法很简单。有 1 个计时器线程运行计时器事件循环并动态添加和删除计时器。定时器是非常简单的倒计时定时器,当它们达到 0 时执行函数指针,并且可以取消。所以不需要重复。
问题
我认为这里真正的问题是文档,libuv 文档对于如何实现这一点并不是很清楚。所以我认为我目前拥有的代码是垃圾。让我带您了解一下。
在我的程序开始时,我使用以下入口点启动一个 phtread:
static void* _uv_loop_thread_entry_point(void *args)
{
/* Initialize the timer event loop */
timer_event_loop = malloc(sizeof(uv_loop_t));
uv_loop_init(timer_event_loop);
/* Keep running the eventloop */
while(uv_run(timer_event_loop, UV_RUN_DEFAULT) == 0) {
/* Wait 1 second for new handles */
sleep(1);
};
/* The timer event loop has stopped, free all resources */
uv_loop_close(timer_event_loop);
free(timer_event_loop);
return NULL;
}
每当我想使用计时器时,我都会执行以下操作:
uv_timer_init(timer_event_loop, uv_timer);
uv_timer_start(uv_timer, timeout_ms, ??);
现在我有几个问题:
- 如何不重复使用定时器
- 这个定时器的回调函数在哪里设置
- 我怎么知道这个计时器还剩多少时间
在这个问题上我真的需要一些帮助。
更新 1
好的,我正在取得一些进展,基本上可以了。 libuv 事件循环在单独的线程中运行。并且已经回答了我的一些问题:
当 uv_timer_start
中的最后一个参数为 0 时,计时器将不会重复。
定时器超时事件的回调是uv_timer_start
的第二个参数
我还不知道第三个问题的最佳答案。但是现在我会记录我的计时器开始的时间和当前时间,并计算两者之间的差异。我然后从计时器的总时间中减去差异,以了解计时器结束之前需要多长时间。
我仍然想知道我的 uv_run
实施是否正确。
亲切的问候,
大安
您正在玩未定义的行为领域。 libuv 不是线程安全的 see the docs here 因此,虽然 运行 一个线程中的循环是可以的,但在另一个线程中创建一个计时器而循环是 运行 则不是。
您仍然可以通过使用 uv_async_t
句柄和信号量来完成此操作:uv_async_send
是线程安全的,因此您可以从外部调用它,停止循环并向信号量发出信号。调用线程将等待信号量发出信号。此时循环停止,那么新建一个timer并添加就可以了。
没有API知道计时器还剩多少时间。
如果你只需要一个循环来控制一些定时器,那么 libuv 可能就太过分了。如果你在 Linux,你可以使用 timerfd,或者一个只在 select 之上做定时器的手工构建的事件循环。
用例
我正在编写一个需要多个计时器的 C 程序。我首先编写了一个快速原型,它为每个计时器启动了一个 pthread
。只是一个带有 sleep
命令的简单 while
循环,因为 1 秒分辨率就足够了。
但是如果有 10 个以上的定时器,它的效率就不是很高,也不是生产级的代码质量。因此我想使用事件循环。我已经多次阅读有关 libuv 的文章,并想尝试一下。
所以我的想法很简单。有 1 个计时器线程运行计时器事件循环并动态添加和删除计时器。定时器是非常简单的倒计时定时器,当它们达到 0 时执行函数指针,并且可以取消。所以不需要重复。
问题
我认为这里真正的问题是文档,libuv 文档对于如何实现这一点并不是很清楚。所以我认为我目前拥有的代码是垃圾。让我带您了解一下。
在我的程序开始时,我使用以下入口点启动一个 phtread:
static void* _uv_loop_thread_entry_point(void *args)
{
/* Initialize the timer event loop */
timer_event_loop = malloc(sizeof(uv_loop_t));
uv_loop_init(timer_event_loop);
/* Keep running the eventloop */
while(uv_run(timer_event_loop, UV_RUN_DEFAULT) == 0) {
/* Wait 1 second for new handles */
sleep(1);
};
/* The timer event loop has stopped, free all resources */
uv_loop_close(timer_event_loop);
free(timer_event_loop);
return NULL;
}
每当我想使用计时器时,我都会执行以下操作:
uv_timer_init(timer_event_loop, uv_timer);
uv_timer_start(uv_timer, timeout_ms, ??);
现在我有几个问题:
- 如何不重复使用定时器
- 这个定时器的回调函数在哪里设置
- 我怎么知道这个计时器还剩多少时间
在这个问题上我真的需要一些帮助。
更新 1
好的,我正在取得一些进展,基本上可以了。 libuv 事件循环在单独的线程中运行。并且已经回答了我的一些问题:
当
uv_timer_start
中的最后一个参数为 0 时,计时器将不会重复。定时器超时事件的回调是
uv_timer_start
的第二个参数
我还不知道第三个问题的最佳答案。但是现在我会记录我的计时器开始的时间和当前时间,并计算两者之间的差异。我然后从计时器的总时间中减去差异,以了解计时器结束之前需要多长时间。
我仍然想知道我的 uv_run
实施是否正确。
亲切的问候, 大安
您正在玩未定义的行为领域。 libuv 不是线程安全的 see the docs here 因此,虽然 运行 一个线程中的循环是可以的,但在另一个线程中创建一个计时器而循环是 运行 则不是。
您仍然可以通过使用 uv_async_t
句柄和信号量来完成此操作:uv_async_send
是线程安全的,因此您可以从外部调用它,停止循环并向信号量发出信号。调用线程将等待信号量发出信号。此时循环停止,那么新建一个timer并添加就可以了。
没有API知道计时器还剩多少时间。
如果你只需要一个循环来控制一些定时器,那么 libuv 可能就太过分了。如果你在 Linux,你可以使用 timerfd,或者一个只在 select 之上做定时器的手工构建的事件循环。