APUE习题10.5之implementing software timer

来源:互联网 发布:xbox one网络 编辑:程序博客网 时间:2024/05/18 07:14

题目:仅使用一个定时器,构造一组函数,使得进程在该单一定时器基础上可以设置任意数量的定时器。

具体思路请见http://www.cnblogs.com/CoreyGao/archive/2013/05/01/3053417.html,这篇译文已详细介绍,本文主要给出相应实现。

 

first mytimer.h

#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <time.h>#include <unistd.h>#include <limits.h>#define TRUE  1#define FALSE 0#define MAX_TIMERS 100 // 最大定时器数#define VERY_LONG_TIME LONG_MAX // 最长定时数typedef time_t TIME; // 隐藏TIME的实现typedef void timer_handler(void *arg); volatile TIME time_now,time_set; // now为当前时间,set为当前定时器设置时间struct sigaction newact,oldact; // 设置sigalrm的处理程序sigset_t newmask,oldmask; // 设置屏蔽字struct timer{int inuse; // true if in useTIME time; // relative time to waittimer_handler *ahandler; // called when the timer has expiredvoid *arg; // arguemtn of handler}timers[MAX_TIMERS];struct timer *timer_next;void  timer_init(void); // 初始化计时器struct timer* timer_declare(TIME,timer_handler*,void*); // 生成一个计时器void timer_undeclare(struct timer*); // 取消一个计时器void timer_update(); // 更新计时器数组,并获得下一个将要计时的计时器void timer_out_handler(int signo); // 信号处理函数void func(void *arg); // 自定义输出函数

second mytimer.c

#include "mytimer.h"static void disable_interrupt(void)  // 关闭中断{sigemptyset(&newmask);sigaddset(&newmask,SIGINT);if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) < 0)fprintf(stderr,"sigprocmask error\n");}static void enable_interrupt(void) // 开启中断{if(sigprocmask(SIG_SETMASK,&oldmask,NULL) < 0)fprintf(stderr,"sigprocmask error\n");}void timer_init(void){int i;disable_interrupt();for(i = 0;i<MAX_TIMERS;i++)timers[i].inuse = FALSE; // 将计时器数组中每个计时器inuse状态设置为未用sigfillset(&newact.sa_mask); // 在处理信号时,阻塞所有信号的递送newact.sa_flags = 0;newact.sa_handler = timer_out_handler;if(sigaction(SIGALRM,&newact,&oldact) < 0){fprintf(stderr,"sigaction error\n");enable_interrupt();return;}enable_interrupt();}struct timer* timer_declare(TIME time_s,timer_handler *handler,void *arg){int i;disable_interrupt();for(i = 0;i<MAX_TIMERS;i++) // 找到第一个未用的计时器if(!timers[i].inuse)break;if(i == MAX_TIMERS) // 所有计时器都已用完{enable_interrupt();return NULL;}timers[i].time = time_s; // 计时器时间timers[i].ahandler = handler; // 计时器处理函数timers[i].arg = arg; // 处理函数参数if(!timer_next) // 当前计时器为唯一计时器{time_set = time(NULL); // 保存当前设置时间alarm((timer_next = &timers[i])->time); // 开始计时}else if(time_s  < (timer_next->time - (time(NULL) - time_set))) // 比较当前计时器和当前正在计时的计时器的时间长度{timer_update(); // 更新每个计时器的计时timer_next = &timers[i]; // 设置新的当前正在计时的计时器time_set = time(NULL); // 记录设置时间alarm(timer_next->time); // 开始计时}timers[i].inuse = TRUE; // 最后再改变inuse防止update干扰enable_interrupt();return &timers[i];}void timer_undeclare(struct timer* t){disable_interrupt();if(!t->inuse){enable_interrupt();return;}t->inuse = FALSE;if(t == timer_next) // 如果是当前正在计时的计时器timer_update();enable_interrupt();}void timer_update() // 更新所有计时器时间,并将时间最短的设置为当前正在计时的计时器。{disable_interrupt();int i;static struct timer timer_last = {FALSE,VERY_LONG_TIME,NULL,NULL};timer_next = &timer_last;time_now = time(NULL); // 读取当前时间for(i = 0;i<MAX_TIMERS;i++){if(timers[i].inuse){timers[i].time -= time_now - time_set; // 所有计时更新if(timers[i].time < timer_next->time)timer_next = &timers[i]; // 更新当前正在计时的计时器}}if(timer_next->inuse) // 如果存在还未发生的定时器{alarm(timer_next->time);time_set = time(NULL);}elsetimer_next = NULL;enable_interrupt();}void timer_out_handler(int signo){timer_next->ahandler(timer_next->arg);timer_next->inuse = FALSE;timer_update(); // 寻找下一个执行的定时器}void func(void* arg){char *p = (char*)arg;printf("%s\n",p);}Contact GitHub API Training Shop Blog About © 2017 GitHub, Inc. Terms Privacy Security Status Help 

third main.c

#include "mytimer.c"int main(){setbuf(stdout,NULL);timer_init();TIME time = 1;timer_declare(time,func,(void*)"hello world");time = 3;struct timer* t =timer_declare(time,func,(void*)"this is a test");time = 5;struct timer* m = timer_declare(time,func,(void*)"func(5)");timer_undeclare(t);while(1)pause();exit(0);}

运行结果

具体项目代码可见:https://github.com/xiaoHzp/apue/tree/master/ch10/simple10_5


原创粉丝点击