apue习题10.5

转自: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();
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值