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需要修改线程创建函数,休眠函数以及相应的头文件。
  • 如有问题及建议可留言,另外创作不易,还望一键三连,多多支持博主,谢谢各位啦~~
posted @ 2021-01-02 16:25  chegxy  阅读(3165)  评论(0编辑  收藏  举报