转自:http://blog.chinaunix.net/uid-738944-id-3395433.html
apue的第十章的习题10.5 仅使用一个计时器(alarm或较高精度的setitimer),构造一组函数,使得进程可以设置任一数目的计时器。
设计下面两个函数
int settimer(int seconds, void (*proc)(int));
int canceltimer(int id);
settimer的返回值是计时器的id(>=0),出错时返回-1.
设计下面这个构造体,
struct timer_t
{
char isused; // 是否有效
int seconds; // 剩余秒数
void (*proc)(int); // 超时调用函数指针
};
实现简单起见,用下面的数组表示多个定时器。
#define TIMERS_MAX 100
struct timer_t timers[TIMERS_MAX];
int curtimer_id; // 当前的定时器ID
具体看代码吧,有考虑不到的情况,请多多指教。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
int opentimer();
void closetimer();
int settimer(int seconds, void (*proc)(int));
int canceltimer(int id);
struct timer_t
{
char isused;
int seconds;
void (*proc)(int);
};
#define TIMERS_MAX 100
struct timer_t timers[TIMERS_MAX];
int curtimer_id;
void (*old_sig_proc)(int);
sigset_t old_sigset;
static int getid()
{
int id = -1;
for (id = 0; id < TIMERS_MAX; id++)
{
if (timers[id].isused == 0)
{
break;
}
}
return id;
}
static int getnexttimer(int cur_id)
{
int id;
int surplus_seconds = 0;
if (cur_id < 0)
{
for (id = 0; id < TIMERS_MAX; id++)
{
if (timers[id].isused == 1)
{
cur_id = id;
break;
}
}
}
if (cur_id < 0)
{
return cur_id;
}
surplus_seconds = timers[cur_id].seconds;
for (id = 0; id < TIMERS_MAX; id++)
{
if (timers[id].isused == 1 && surplus_seconds > timers[id].seconds)
{
surplus_seconds = timers[id].seconds;
cur_id = id;
}
}
return cur_id;
}
static void resetseconds(int over_seconds)
{
int id = 0;
for (id = 0; id < TIMERS_MAX; id++)
{
if (timers[id].isused == 1)
{
timers[id].seconds -= over_seconds;
}
}
return;
}
static void alarm_proc(int signo)
{
void (*cur_proc)(int);
int cur_id;
resetseconds(timers[curtimer_id].seconds);
timers[curtimer_id].isused = 0;
cur_proc = timers[curtimer_id].proc;
cur_id = curtimer_id;
curtimer_id = getnexttimer(-1);
if (signal(SIGALRM, alarm_proc) == SIG_ERR)
{
exit(-1);
}
alarm(timers[curtimer_id].seconds);
cur_proc(cur_id);
}
int opentimer()
{
sigset_t new_sigset;
curtimer_id = -1;
memset(timers, 0, sizeof(timers));
// cancel previous alarm
alarm(0);
old_sig_proc = signal(SIGALRM, NULL);
// UNBLOCK SIGALRM
sigemptyset(&new_sigset);
sigaddset(&new_sigset, SIGALRM);
if (sigprocmask(SIG_UNBLOCK, &new_sigset, &old_sigset) < 0)
{
return -1;
}
return 0;
}
void closetimer()
{
alarm(0);
curtimer_id = -1;
memset(timers, 0, sizeof(timers));
if (sigprocmask(SIG_SETMASK, &old_sigset, NULL) < 0)
{
exit(1);
}
}
int settimer(int seconds, void (*proc)(int))
{
int id = -1;
int surplus_seconds = 0;
int over_seconds = 0;
void (*retfunc)(int);
id = getid();
if (id < 0)
{
return id;
}
timers[id].seconds = seconds;
timers[id].proc = proc;
timers[id].isused = 1;
surplus_seconds = alarm(0);
if (surplus_seconds > 0)
{
over_seconds = timers[curtimer_id].seconds - surplus_seconds;
resetseconds(over_seconds);
}
curtimer_id = getnexttimer(id);
if (signal(SIGALRM, alarm_proc) == SIG_ERR)
{
return -1;
}
alarm(timers[curtimer_id].seconds);
return id;
}
int canceltimer(int cancel_id)
{
int surplus_seconds = 0;
int over_seconds;
if (timers[cancel_id].isused == 0)
{
return 0;
}
if (cancel_id != curtimer_id)
{
timers[cancel_id].isused = 0;
timers[cancel_id].seconds = 0;
timers[cancel_id].proc = NULL;
return 0;
}
surplus_seconds = alarm(0);
over_seconds = timers[curtimer_id].seconds - surplus_seconds;
resetseconds(over_seconds);
timers[cancel_id].isused = 0;
timers[cancel_id].seconds = 0;
timers[cancel_id].proc = NULL;
curtimer_id = getnexttimer(-1);
if (signal(SIGALRM, alarm_proc) == SIG_ERR)
{
return -1;
}
alarm(timers[curtimer_id].seconds);
return 0;
}
void proc1(int id)
{
printf("proc1 id:%d\n", id);
//settimer(5, proc1);
return;
}
void proc2(int id)
{
printf("proc2 id:%d\n", id);
return;
}
void proc3(int id)
{
printf("proc3 id:%d\n", id);
return;
}
int main(int argc, char *argv[ ])
{
int id1, id2, id3;
id1 = settimer(10, proc1);
id2 = settimer(5, proc2);
id3 = settimer(8, proc3);
canceltimer(id3);
id3 = settimer(15, proc3);
while (1)
pause();
}