博客
关于我
C 实现一个跨平台的定时器 论述
阅读量:440 次
发布时间:2019-03-06

本文共 3347 字,大约阅读时间需要 11 分钟。

跨平台多线程C定时器对象开发与实现

引言

本文将介绍并实现一个跨平台、支持多线程的简易定时器对象,粒度为毫秒级别。该定时器对象通过sctimer.h库实现,适用于需要异步、非阻塞定时任务的高效场景。

接口概览

首先,我们来看定时器的核心接口——st_add:

extern int st_add(int start, int cut, int intval, vdel_f timer, void* arg, bool fb);

该函数接收以下参数:

  • start:延迟启动时间,0表示立即启动,单位为毫秒。
  • cut:执行次数,0表示永久循环,1表示单次执行。
  • intval:每次执行的间隔时间,单位为毫秒。
  • timer:定时器执行的函数指针。
  • arg:函数调用的参数指针。
  • fb:启用多线程标志,true表示异步执行,false表示同步执行。

该函数返回定时器的唯一ID。

数据结构设计

定时器的核心数据结构为stnode,表示单个定时器对象:

struct stnode {    int id;          // 定时器的唯一ID    time_t stime;    // 最早执行时间(秒)    int ms;          // 剩余等待时间(毫秒)    int cut;        // 剩余执行次数    int intval;      // 下次执行间隔(毫秒)    int type;       // 定时器类型:0表示同步,1表示异步    vdel_f timer;    // 定时器执行函数    void* arg;      // 函数参数    struct stnode* next; // 下一个定时器对象指针};

定时器管理的核心结构为stlist,用于管理多个定时器对象:

struct stlist {    int lock;         // 加锁标志    int nowid;       // 已使用的最大定时器ID    int status;      // 状态:0表示停止,1表示运行中    pthread_t tid;    // 主循环线程ID    struct stnode* head; // 定时器链表头节点};

业务逻辑设计

添加定时器

st_add函数负责将定时器对象添加到管理链表中,并启动相应的执行线程:

int st_add(int start, int cut, int intval, vdel_f timer, void* arg, bool fb) {    struct stnode* now = _new_stnode(start, cut, intval, timer, arg, fb);    _stlist_add(&_st, now);    return now->id;}

删除定时器

st_del函数负责删除指定ID的定时器对象:

inline void st_del(int st) {    struct stnode* sn = _stlist_del(&_st, st);    if (sn) free(sn);}

定时器执行机制

定时器的核心执行逻辑在_stlist_loop函数中:

static void* _stlist_loop(struct stlist* st) {    while (st->head) {        pthread_testcancel();        int nowt = _sleeptime(st);        if (nowt <= 0 || st->head->cut == 1) {            _slnode_again_run(st);        } else {            SLEEPMS(nowt);        }    }    st->status = 0;    return NULL;}

多线程支持

定时器支持两种模式:同步和异步。异步模式通过线程池实现,以避免主线程阻塞:

static void* _slnode_timer(struct stnode* sn) {    pthread_detach(pthread_self());    sn->timer(sn->arg);    return NULL;}static void _slnode_again_run(struct stlist* st) {    struct stnode* sn = st->head;    st->head = sn->next;    if (sn->cut == 1) {        free(sn);        return;    }    sn->cut = (sn->cut > 0) ? sn->cut - 1 : 0;    int s = sn->intval + sn->ms;    sn->stime += s / 1000;    sn->ms = s % 1000;        if (sn->type) {        pthread_t tid;        pthread_create(&tid, NULL, (void* (*)(void*))_slnode_timer, sn);    } else {        sn->timer(sn->arg);    }    _stlist_add(st, sn);}

跨平台支持

为了实现跨平台支持,特别是Windows和Linux的差异,我们引入了原子锁和时间获取函数:

// 跨平台原子锁#define _INT_USLEEP (2)#define ATOM_LOCK(v) while(ATOM_SET(v, 1)) usleep(_INT_USLEEP)// 时间获取#if defined(_MSC_VER)#include 
#include
#define SLEEPMS(m) Sleep(m)extern int gettimeofday(struct timeval* tv, void* tz);#else#include
#include
#define SLEEPMS(m) usleep(m * 1000)#endif

测试与验证

测试代码test_sctimer.c展示了定时器的使用场景:

#include 
static int _sm = 0;static void _timer(void* arg) { char tstr[64]; sh_times(tstr, 64); printf("%p + %d => %s\n", arg, ++_sm, tstr);}int main(int argc, char* argv) { st_add(0, 5, 2000, _timer, (void*)1, false); st_add(3000, 2, 2000, _timer, (void*)2, false); st_add(4000, 1, 2000, _timer, (void*)3, false); int tid = st_add(0, 0, 1000, _timer, (void*)4, true); SLEEPMS(5000); st_del(tid); st_add(100, 0, 5000, _timer, (void*)5, false); sh_pause(); return 0;}

总结

通过以上设计,我们成功实现了一个跨平台、支持多线程的简易定时器对象。该定时器对象兼顾了异步执行、线程安全和高效性能,适用于需要定时任务调度的复杂应用场景。

转载地址:http://hniyz.baihongyu.com/

你可能感兴趣的文章
Python 中的装饰器是什么?
查看>>
Python 中的装饰器是如何工作的,有哪些实际应用场景?
查看>>
python读excel
查看>>
Python 中读取 CSV 文件-ChatGPT4o作答
查看>>
python请求html_使用Python请求获取HTML?
查看>>
Python 之匿名函数和偏函数
查看>>
python 之栈的实现
查看>>
python语音播放
查看>>
python语言:装饰器原理
查看>>
Python 交互式数据可视化详解
查看>>
python语言有哪些优点和缺点_Python有哪些优缺点,你了解吗?
查看>>
Python 从入门到精通:30天速成教程到底有多狠?你能坚持下来吗?
查看>>
Python 从数据库中存储和检索密码的最安全方法
查看>>
Python语言及其应用 - 知识点遍历
查看>>
Python 优化提速的 8 个小技巧
查看>>
Python 余弦相似度与皮尔逊相关系数 计算
查看>>
python 使用execjs 报编码错误解决办法,UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0xac in position 145: il
查看>>
python 使用filetype校验文件
查看>>
Python 使用flush函数将缓冲区数据立即写磁盘
查看>>
python 使用in判断不准确,in不好使
查看>>