C语言实现任务调度与定时器
代码实现是在xl2tpd的源码中get到的,感觉很有意思的一段代码。基本功能就是实现定时器,时间到后从定时队列中取出,然后完成指定的任务。
1. schedule.c代码(自己添加了main函数,用来调试)
/** Layer Two Tunnelling Protocol Daemon* Copyright (C) 1998 Adtran, Inc.* Copyright (C) 2002 Jeff McAdams** Mark Spencer** This software is distributed under the terms* of the GPL, which you should have received* along with this source.** Scheduler code for time based functionality**/
#include
#include
#include
#include
#include "scheduler.h"struct schedule_entry *events;
static struct timeval zero;
static sigset_t alarm;/*init_scheduler配合schedule_lock,schedule_unlock使用,用来屏蔽当前进程中特定协议的处理
*/
void init_scheduler (void)/*初始化了两个不同的信号集*/
{struct sigaction act;act.sa_handler = alarm_handler;/*alarm信号执行体*/
#if defined (LINUX) && (__i386__)act.sa_restorer = NULL;
#endifact.sa_flags = 0;sigemptyset (&act.sa_mask);sigaddset (&act.sa_mask, SIGALRM);/*将SIGALRM信号添加到信号集sa_mask中,SIGALRM信号会阻塞*/sigaction (SIGALRM, &act, NULL);/*安装登记信号*/events = NULL;zero.tv_usec = 0;zero.tv_sec = 0;sigemptyset (&alarm);sigaddset (&alarm, SIGALRM);/*将SIGALRM信号添加到信号集alarm中,SIGALRM信号会阻塞*/
}void alarm_handler (int signal)
{/* Check queue for events which should beexecuted right now. Execute them, thensee how long we should set the next timer*/struct schedule_entry *p = events;struct timeval now;struct timeval then;struct itimerval itv;static int cnt = 0;cnt++;if (cnt != 1){/* Whoa, we got called from within ourselves! *///log (LOG_DEBUG, "%s : Whoa... cnt = %d\n", __FUNCTION__, cnt);return;}while (events){gettimeofday (&now, NULL);p = events;if (TVLESSEQ (p->tv, now)){events = events->next;/* This needs to be executed, as it has expired.It is expected that p->func will free p->dataif it is necessary */(*p->func) (p->data);free (p);}elsebreak;}/* When we get here, either there are no more eventsin the queue, or the remaining events need to happenin the future, so we should schedule another alarm */if (events){then.tv_sec = events->tv.tv_sec - now.tv_sec;then.tv_usec = events->tv.tv_usec - now.tv_usec;if (then.tv_usec < 0){then.tv_sec -= 1;then.tv_usec += 1000000;}if ((then.tv_sec <= 0) && (then.tv_usec <= 0)){//log (LOG_WARN, "%s: Whoa... Scheduling for <=0 time???\n",__FUNCTION__);}else{itv.it_interval = zero;itv.it_value = then;setitimer (ITIMER_REAL, &itv, NULL);/*重新定时,时间到后发送SIGALRM信号*/}}cnt--;
}void schedule_lock ()/*将alarm添加到当前进程阻塞信号集中,信号来时会被阻塞,暂时捕获不到,移除后会捕获?/
{while (sigprocmask (SIG_BLOCK, &alarm, NULL));
};void schedule_unlock ()/*将alarm从当前进程阻塞信号集中移除*/
{/* See if we missed any events */
/* alarm_handler(0); */while (sigprocmask (SIG_UNBLOCK, &alarm, NULL));raise (SIGALRM);/*用来向本进程发送信号*/
};struct schedule_entry *schedule (struct timeval tv, void (*func) (void *),void *data)
{/* Schedule func to be run at relative time tv with dataas arguments. If it has already expired, run it immediately. The queue should be in order ofincreasing time */struct schedule_entry *p = events, *q = NULL; /*时间间隔递增的队列*/int need_timer = 0;struct timeval diff;struct itimerval itv; /*队列中越靠前,越早发生*/diff = tv;gettimeofday (&tv, NULL);tv.tv_sec += diff.tv_sec; /*转换为本地系统时间*/tv.tv_usec += diff.tv_usec;if (tv.tv_usec > 1000000){tv.tv_sec++;tv.tv_usec -= 1000000;/*进制转换*/}while (p) {if (TVLESS (tv, p->tv)) /*tv < p->tv*/break;q = p;p = p->next;};if (q){q->next =(struct schedule_entry *) malloc (sizeof (struct schedule_entry));q = q->next;}else{ /*时间比队列中的第一个时间还小*/q = (struct schedule_entry *) malloc (sizeof (struct schedule_entry));events = q;need_timer = -1;}q->tv = tv;q->func = func;q->data = data;q->next = p;if (need_timer){itv.it_interval = zero;itv.it_value = diff;setitimer (ITIMER_REAL, &itv, NULL); /*重新修改定时*/}return q;}inline struct schedule_entry *aschedule (struct timeval tv,/*tv传递的为绝对时间*/void (*func) (void *), void *data)
{/* Schedule func to be run at absolute time tv in the future with dataas arguments */struct timeval now;gettimeofday (&now, NULL);tv.tv_usec -= now.tv_usec;if (tv.tv_usec < 0){tv.tv_usec += 1000000;tv.tv_sec--;}tv.tv_sec -= now.tv_sec;return schedule (tv, func, data);
}void deschedule (struct schedule_entry *s)/*取消任务*/
{struct schedule_entry *p = events, *q = NULL;if (!s)return;while (p){if (p == s){if (q){q->next = p->next;}else{events = events->next;}free (p);break;}q = p;p = p->next;}
}
/*****************************************************************/
void func_test(void *data)
{struct timeval tv; tv.tv_sec = 5;tv.tv_usec = 0;printf("落霞与孤鹜齐飞,秋水共长天一色\n");schedule(tv, func_test, NULL);
}void main(int argc, char *argv[])
{struct timeval tv;struct timeval timeout;printf("------scheduler-------\n");init_scheduler ();tv.tv_sec = 5;tv.tv_usec = 0;schedule(tv, func_test, NULL);timeout.tv_sec = 1;timeout.tv_usec = 0;while(1){select(0,NULL,NULL,NULL, &timeout);}
}
2. schedule.h
/** Layer Two Tunnelling Protocol Daemon* Copyright (C) 1998 Adtran, Inc.* Copyright (C) 2002 Jeff McAdams** Mark Spencer** This software is distributed under the terms* of the GPL, which you should have received* along with this source.** Scheduler structures and functions**/#ifndef _SCHEDULER_H
#define _SCHEDULER_H
#include /** The idea is to provide a general scheduler which can schedule* events to be run periodically*/struct schedule_entry
{struct timeval tv; /* Scheduled time to execute */void (*func) (void *); /* Function to execute */void *data; /* Data to be passed to func */struct schedule_entry *next; /* Next entry in queue */
};extern struct schedule_entry *events;/* Schedule func to be executed with argument data sometimetv in the future. */struct schedule_entry *schedule (struct timeval tv, void (*func) (void *),void *data);/* Like schedule() but tv represents an absolute time in the future */struct schedule_entry *aschedule (struct timeval tv, void (*func) (void *),void *data);/* Remove a scheduled event from the queue */void deschedule (struct schedule_entry *);/* The alarm handler */void alarm_handler (int);/* Initialization function */
void init_scheduler (void);/* Prevent the scheduler from running */
void schedule_lock ();/* Restore normal scheduling functions */
void schedule_unlock ();/* Compare two timeval functions and see if a <= b */#define TVLESS(a,b) ((a).tv_sec == (b).tv_sec ? \((a).tv_usec < (b).tv_usec) : \((a).tv_sec < (b).tv_sec))
#define TVLESSEQ(a,b) ((a).tv_sec == (b).tv_sec ? \((a).tv_usec <= (b).tv_usec) : \((a).tv_sec <= (b).tv_sec))
#define TVGT(a,b) ((a).tv_sec == (b).tv_sec ? \((a).tv_usec > (b).tv_usec) : \((a).tv_sec > (b).tv_sec))
#endif
3. 最简单的Makefile
CC = gcc
CFLAGS = -g
LFLAGS =
OBJS = scheduler.o
all : scheduler
scheduler : $(OBJS)$(CC) $^ -o $@ $(LFLAGS)%*.o:%*.c$(CC) $(CFLAGS) $< -o $@.PHNOY: clean
clean:rm *.o scheduler
4. demo结果
调度时,每隔5秒钟,执行一次func_tesr()。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!