从0到1掌握libhv定时器:让你的任务调度如丝般顺滑
你是否还在为网络编程中的定时任务调度烦恼?定时器不准、内存泄漏、复杂任务难以管理?本文将带你全面掌握libhv网络库中定时器回调的使用方法,从基础API到高级任务调度,让你的定时任务处理既高效又可靠。读完本文,你将能够轻松实现单次定时、周期性任务、Cron风格调度等功能,并了解多线程环境下的定时器安全使用技巧。
定时器基础:核心数据结构与API
libhv的定时器功能主要通过hloop_t事件循环和htimer_t定时器对象实现,相关定义位于event/hloop.h头文件中。
核心数据类型
- hloop_t: 事件循环对象,负责管理所有定时器事件的注册、触发和销毁
- htimer_t: 定时器对象,代表一个具体的定时任务
- htimer_cb: 定时器回调函数类型,定义为
void (*htimer_cb)(htimer_t* timer)
基础API概览
// 创建定时器
htimer_t* htimer_add(hloop_t* loop, htimer_cb cb, uint32_t timeout_ms, uint32_t repeat);
// 删除定时器
void htimer_del(htimer_t* timer);
// 重置定时器
void htimer_reset(htimer_t* timer, uint32_t timeout_ms);
其中timeout_ms参数指定定时时间(毫秒),repeat参数指定重复次数(INFINITE表示无限重复)。
快速上手:第一个定时器程序
让我们从一个简单的示例开始,创建一个每隔1秒触发一次的定时器。完整代码可参考examples/htimer_test.c。
单次定时器
#include "hloop.h"
// 定时器回调函数
void on_timer(htimer_t* timer) {
printf("定时器触发!当前时间: %llu ms\n", hloop_now_ms(hevent_loop(timer)));
}
int main() {
// 创建事件循环
hloop_t* loop = hloop_new(0);
// 添加定时器:3秒后触发,仅执行一次
htimer_add(loop, on_timer, 3000, 1);
// 运行事件循环
hloop_run(loop);
// 释放资源
hloop_free(&loop);
return 0;
}
周期性定时器
要创建周期性定时器,只需将repeat参数设为INFINITE:
// 添加周期性定时器:每隔1秒触发一次
htimer_add(loop, on_timer, 1000, INFINITE);
编译与运行
使用Makefile编译示例程序:
make examples
./examples/htimer_test
运行后,你将看到定时器按预期触发。
高级功能:Cron风格调度
libhv提供了类似Cron的定时任务调度功能,通过htimer_add_period函数实现,可以按分钟、小时、日、周、月等周期调度任务。
Cron API定义
htimer_t* htimer_add_period(hloop_t* loop, htimer_cb cb,
int8_t minute, int8_t hour, int8_t day,
int8_t week, int8_t month, uint32_t repeat);
参数说明:
- minute: 分钟 (0-59)
- hour: 小时 (0-23)
- day: 日 (1-31)
- week: 星期 (0-6, 0表示周日)
- month: 月 (1-12)
- repeat: 重复次数
实用示例
// 每小时触发一次(整点触发)
htimer_add_period(loop, cron_hourly, 0, -1, -1, -1, -1, INFINITE);
// 每天凌晨3点30分触发
htimer_add_period(loop, daily_task, 30, 3, -1, -1, -1, INFINITE);
// 每周五下午4点触发
htimer_add_period(loop, weekly_task, 0, 16, -1, 5, -1, INFINITE);
examples/htimer_test.c中提供了完整的Cron风格调度示例,你可以参考学习。
定时器管理:删除与重置
在实际应用中,我们经常需要动态管理定时器,如取消定时任务或调整定时时间。
删除定时器
// 创建定时器并保存句柄
htimer_t* timer = htimer_add(loop, on_timer, 1000, INFINITE);
// 在需要时删除定时器
htimer_del(timer);
重置定时器
// 重置定时器为2秒后触发
htimer_reset(timer, 2000);
// 如果timeout_ms为0,则使用原来的间隔
htimer_reset(timer, 0);
下面是一个重置定时器的完整示例:
void on_timer_reset(htimer_t* timer) {
static int count = 0;
printf("第%d次触发,即将重置定时器\n", ++count);
if (count >= 5) {
// 5次后重置为3秒间隔
htimer_reset(timer, 3000);
printf("定时器已重置为3秒间隔\n");
}
}
// 在main函数中
htimer_add(loop, on_timer_reset, 1000, INFINITE);
高级应用:定时器优先级与多线程安全
libhv定时器支持设置优先级,可用于实现任务的分级调度。同时,libhv保证了定时器操作的线程安全性。
设置定时器优先级
htimer_t* timer = htimer_add(loop, on_timer, 1000, INFINITE);
hevent_set_priority(timer, HEVENT_HIGH_PRIORITY); // 设置高优先级
优先级取值范围从HEVENT_LOWEST_PRIORITY(-5)到HEVENT_HIGHEST_PRIORITY(5),默认为HEVENT_NORMAL_PRIORITY(0)。
多线程环境下使用
在多线程环境中,可以安全地调用htimer_add、htimer_del和htimer_reset函数。如果需要从其他线程触发定时器事件,可以使用hloop_post_event函数:
// 在工作线程中发送事件到事件循环线程
hevent_t ev;
memset(&ev, 0, sizeof(ev));
ev.loop = loop;
ev.cb = on_custom_event;
ev.userdata = "来自工作线程的消息";
hloop_post_event(loop, &ev);
实战技巧:定时器常见问题解决方案
避免回调函数阻塞
定时器回调函数应尽快执行完毕,避免阻塞事件循环。如果需要执行耗时操作,建议将其放入线程池处理:
#include "hthreadpool.h"
void long_running_task(void* arg) {
// 耗时操作...
}
void on_timer(htimer_t* timer) {
// 将耗时任务提交到线程池
hthreadpool_post(hthreadpool_get_global(), long_running_task, NULL);
}
定时器精度控制
libhv使用系统时钟实现定时器,精度通常在毫秒级别。如果需要更高精度的定时,可以考虑使用hloop_now_hrtime函数获取高精度时间戳进行补偿。
void on_precise_timer(htimer_t* timer) {
static uint64_t last_time = 0;
uint64_t now = hloop_now_hrtime(hevent_loop(timer));
if (last_time > 0) {
printf("实际间隔: %llu us\n", now - last_time);
}
last_time = now;
}
总结与进阶学习
通过本文的介绍,你已经掌握了libhv定时器的基本使用方法和高级特性。libhv定时器模块以其简洁的API和可靠的性能,为网络应用中的任务调度提供了强大支持。
进阶学习资源
- 官方文档:docs/cn/hloop.md
- 示例代码:examples/htimer_test.c
- 事件循环实现:event/hloop.c
下一步
尝试使用libhv定时器实现以下功能:
- 实现一个定时日志轮转器
- 使用Cron风格定时器实现每日数据备份
- 结合网络模块实现定时心跳检测
希望本文能帮助你更好地利用libhv的定时器功能,构建高效可靠的网络应用!如果你有任何问题或建议,欢迎在项目仓库中提交issue。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



