C语言实现多线程定时器实例讲解
chegxy 人气:0在本篇文章里小编给各位分享的是一篇关于C语言实现多线程定时器实例讲解内容,有需要的朋友们可以参考学习下。
1. 大致功能介绍
- 实现任务列表,定时器会间隔一段时间遍历列表发现要执行的任务
- 任务列表中的所有任务并行执行
- 每个任务都可以有自己的定时器,并且可以选择是否要重复执行
- 定义方便的任务函数实现接口
- 定时器可以由用户自定义何时启动和停止
- 提供等待功能,保证任务列表中的所有任务执行完成
- 提供任务列表的传参功能
2. API库介绍
void setTick(int val);
设置定时间的间隔时间tick,若设置tick为1000,且任务的定时器时间为1000,则任务会在1秒后执行,默认tick为1秒,最小tick时间为1us。
void addTimerTask(TimerTask task, int val, int autoreset, void *arg);
向任务列表注册一个任务,并指定其定时时间val,以及是否要重复执行autoreset,并可以指定参数的地址。
task需要按照头文件提供的宏来编写,例如:
TASK_START(test2, arg) //body Arg *temp = (Arg*)arg; temp->ret = temp->a + temp->b; printf("This is a test2\n"); TASK_END
TASK_START(name, arg)是任务头,name是任务名,arg是参数地址,TASK_END是任务结尾。任务体内可编写正常的c语言代码,并使用参数arg指针。
autoreset有两个可选项:AUTORESET(重复执行),NORESET(执行一次)。
若没有参数,可将arg参数设置为NULL。
void TimerWait();
用于等待任务列表中所有任务执行完毕。
void TimerStop();
用于停止定时器。
void StartTimer();
用于启动定时器。
3. 一个例子
#include <stdio.h> #include "timer.h" typedef struct Argument{ int a; int b; int ret; }Arg; //任务1,打印语句 TASK_START(test1, arg) printf("This is a test1\n"); TASK_END //任务2,计算arg中两个数的和,打印语句 TASK_START(test2, arg) Arg *temp = (Arg*)arg; temp->ret = temp->a + temp->b; printf("This is a test2\n"); TASK_END //任务3,打印语句 TASK_START(test3, arg) printf("This is a test3\n"); TASK_END void main(){ Arg arg; //设置tick 为 500ms setTick(500 * 1000); //添加任务1到任务列表,设置定时器时间为2.5s,重复执行,无参数 addTimerTask(test1, 5, AUTORESET, NULL); arg.a = 2; arg.b = 3; //添加任务2到任务列表,设置定时器时间为0.5s,不重复执行,参数为arg addTimerTask(test2, 1, NORESET, &arg); //添加任务3到任务列表,设置定时器时间为1s,重复执行,无参数 addTimerTask(test3, 2, AUTORESET, NULL); //启动定时器 StartTimer(); printf("Timer is started\n"); //程序等待5秒 sleep(5); //停止定时器 TimerStop(); //等待所有任务执行完毕 TimerWait(); //打印任务二的计算结果 printf("%d\n", arg.ret); }
运行结果:
4. 库文件源码
timer.h:
#ifndef TIMER_H #define TIMER_H #include <unistd.h> #include <stdio.h> #include <pthread.h> #include <stdlib.h> #include <signal.h> #define AUTORESET 1 #define NORESET 0 #define TASK_START(name, arg) void* name(void *arg){ #define TASK_END return NULL;} typedef void* (*TimerTask)(void* arg); struct TaskItem{ TimerTask task; int init_counter; int counter; pthread_t th; void *arg; void *ret; int flag; int autoreset; struct TaskItem *next; }; void setTick(int val); void* EventLoop(void* arg); void addTimerTask(TimerTask task, int val, int autoreset, void *arg); void TimerWait(); void TimerStop(); void StartTimer(); #endif //TIMER_H
timer.cpp
#include "timer.h" #define STOPFLAG 0 #define RUNFLAG 1 static int tick = 1000 * 1000; static struct TaskItem head = { .next = NULL, }; static pthread_t loop_thread; static int flag = STOPFLAG; static int tasknum = 0; void setTick(int val){ tick = val; } void* EventLoop(void* arg){ struct TaskItem *task = head.next; struct TaskItem *pretask = &head; while(flag == RUNFLAG && tasknum > 0){ while(task != NULL){ if(task->counter == 0){ // it is time for doing task if(task->flag == STOPFLAG){ // task is not created if(0 != pthread_create(&(task->th), NULL, task->task, task->arg)){ // do a task printf("Failed to create user's task"); } else{ task->flag = RUNFLAG; } } else{ if(0 != pthread_kill(task->th, 0)){ // current task is completed if(task->autoreset == AUTORESET){ // repeat execute task->counter = task->init_counter; task->flag = STOPFLAG; } else{ // delete a task pretask->next = task->next; free(task); task = pretask->next; tasknum--; continue; } } } } else{ task->counter--; } pretask = pretask->next; task = task->next; } usleep(tick); // sleep a tick task = head.next; pretask = &head; } flag = STOPFLAG; } void addTimerTask(TimerTask task, int val, int autoreset, void *arg){ struct TaskItem *node; node = (struct TaskItem*)malloc(sizeof(struct TaskItem)); node->next = head.next; head.next = node; node->arg = arg; node->counter = val; node->init_counter = val; node->task = task; node->flag = STOPFLAG; node->autoreset = autoreset; tasknum++; } void TimerWait(){ pthread_join(loop_thread, NULL); } void TimerStop(){ flag = STOPFLAG; } void StartTimer(){ flag = RUNFLAG; if(0 != pthread_create(&loop_thread, NULL, EventLoop, NULL)){ printf("Failed to create loop task.\n"); } }
注意事项
- 编译要加 -l pthread选项
- 库实现在Linux环境,如果是windows需要修改线程创建函数,休眠函数以及相应的头文件。
加载全部内容