题目:仅使用一个定时器,构造一组函数,使得进程在该单一定时器基础上可以设置任意数量的定时器。
具体思路请见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 use
TIME time; // relative time to wait
timer_handler *ahandler; // called when the timer has expired
void *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);
}else
timer_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