博客
关于我
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/

你可能感兴趣的文章
NLP 项目:维基百科文章爬虫和分类【01】 - 语料库阅读器
查看>>
NLP_什么是统计语言模型_条件概率的链式法则_n元统计语言模型_马尔科夫链_数据稀疏(出现了词库中没有的词)_统计语言模型的平滑策略---人工智能工作笔记0035
查看>>
NLP三大特征抽取器:CNN、RNN与Transformer全面解析
查看>>
NLP学习笔记:使用 Python 进行NLTK
查看>>
NLP度量指标BELU真的完美么?
查看>>
NLP的不同研究领域和最新发展的概述
查看>>
NLP的神经网络训练的新模式
查看>>
NLP采用Bert进行简单文本情感分类
查看>>
NLP问答系统:使用 Deepset SQUAD 和 SQuAD v2 度量评估
查看>>
NLP项目:维基百科文章爬虫和分类【02】 - 语料库转换管道
查看>>
NLP:使用 SciKit Learn 的文本矢量化方法
查看>>
nmap 使用方法详细介绍
查看>>
Nmap扫描教程之Nmap基础知识
查看>>
nmap指纹识别要点以及又快又准之方法
查看>>
Nmap渗透测试指南之指纹识别与探测、伺机而动
查看>>
Nmap端口扫描工具Windows安装和命令大全(非常详细)零基础入门到精通,收藏这篇就够了
查看>>
NMAP网络扫描工具的安装与使用
查看>>
NMF(非负矩阵分解)
查看>>
nmon_x86_64_centos7工具如何使用
查看>>
NN&DL4.1 Deep L-layer neural network简介
查看>>