C語言實現的多執行緒定時器
阿新 • • 發佈:2021-01-03
目錄
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需要修改執行緒建立函式,休眠函式以及相應的標頭檔案。
- 如有問題及建議可留言,另外創作不易,還望一鍵三連,多多支援博主,謝謝各位啦~~