博客园  :: 首页  :: 新随笔  :: 管理

3.2.1 定时器的几种实现方案

Posted on 2023-03-14 00:11  wsg_blog  阅读(54)  评论(0编辑  收藏  举报

Linux C/C++服务器

定时器的几种实现方案

定时器的应用

  • 网络心跳检测
  • 游戏技能冷却
  • 倒计时
  • 其他需要延时处理的功能

定时器的触发方式

  • 网络事件和定时事件在一个线程处理

通常使用在定时任务比较少的场景,redis、nginx、memcached都是这样处理定时任务的,通常最多组织1024个定时器

// 网络事件和定时事件在一个线程中处理
while (!quit) {
    int timeout = get_nearest_timer() - now();
    if (timeout < 0) timeout = -1;
    int nevent = epoll_wait(epfd, ev, nev, timeout);
    for (int i=0; i<nevent; i++) {
        // ... 处理网络事件
    }
    // 处理定时事件
    update_timer();
}
  • 网络事件和定时事件在不同的线程中处理

适用于定时任务比较多的场景,skynet等,通常使用时间轮数据结构进行实现(加锁力度比较小),定时器检测为单独的线程,执行通过信号或者插入执行队列让其他线程执行

// 网络事件和定时事件在不同线程中处理
void * thread_timer(void *thread_param) {
    init_timer();
    while (!quit) {
      update_timer();
      sleep(t);
    }
    clear_timer();
    return NULL;
}

pthread_create(&pid, NULL, thread_timer, &thread_param);

定时器设计

接口设计

// 初始化定时器
void init_timer();
// 添加定时器
Node* add_timer(int expire, callback cb);
// 删除定时器
bool del_timer(Node* node);
// 找到最近要触发的定时任务
Node* find_nearest_timer();
// 更新检测定时器
void update_timer();
// 清除定时器
// void clear_timer();

数据结构设计

本质就是按照定时任务的优先级进行组织

  • 按照触发时间顺序进行组织:红黑树(绝对有序)、最小堆(相对有序)、跳表(绝对有序)
  • 按照执行顺序进行组织:时间轮

定时器代码