[待解决]重新捕捉定时器信号,是否需要再次调用setitimer函数

#include <curses.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#define MESG  "xxxxxxx"#define BLANK "           "
#define COLUMS 100
int settimer(int);
void move_(int);
void keyboard(int);
int x = 80;
int y = 0;
int dir = -1;
int ppp = 0;
int main(void)
{
    int flag;
    struct itimerval old;
    initscr();
    crmode();
    noecho();
    clear();    
    signal(SIGIO, keyboard);
    fcntl(0, F_SETOWN, getpid());
    flag = fcntl(0, F_GETFL);   
    fcntl(0, F_SETFL, (flag | O_ASYNC));
    signal(SIGALRM, move_);
    settimer(150);
    mvaddstr(y, x, MESG);
    refresh();
    while(1){
    sleep(1);
    getitimer(ITIMER_REAL, &old);
    //printf("P %d %d %d %d\n", (int)old.it_value.tv_sec, (int)old.it_value.tv_usec, (int)old.it_interval.tv_sec, (int)old.it_interval.tv_usec);

    if (ppp == 1) { 
        signal(SIGALRM, SIG_IGN);
        ppp = 0;
    }

    if (ppp == 2) {
        settimer(150);
        signal(SIGALRM, move_);
        ppp = 0;
    }
    }
    endwin();
    }
    int settimer(int msec)
    {
    struct itimerval time_val;
    long sec, usec;
    sec =  msec/1000;
    usec = (msec%1000) * 1000L;
    time_val.it_interval.tv_sec = sec;
    time_val.it_interval.tv_usec = usec;
    time_val.it_value.tv_sec = sec;
    time_val.it_value.tv_usec = usec;
    return setitimer(ITIMER_REAL, &time_val, NULL);
    }   
    void move_(int signum)
    {
    signal(SIGALRM, SIG_IGN);
    mvaddstr(y, x, BLANK);
    if (dir == -1 && y == 0) 
        dir =1;
    if (dir == 1 && y == LINES - 1)
        dir = -1;
    y += dir;
    mvaddstr(y, x, MESG);
    refresh();
    signal(SIGALRM, move_);
    }
    void keyboard(int signum)
    {
    int c;c = getch();if (c == ' ')
    dir = -dir;if (c == 'p')
    ppp = 1;if (c == 'c')
    ppp = 2;
    }

程序描述:

程序包括定时器中断和输入终端,来实现一串字符串在屏蔽上移动。

定时器中断:特定时间间隔使字符串在屏幕上移动一定位置。

输入中断:使用户不必阻塞在接收输入字符上,一旦有输入到来,触发输入中断。根据不同输入字符改变字符串运行状态。

问题描述:

1、为防止在处理定时器中断时,新的定时器中断到来,在进入定时器处理函数时,忽略了定时器信号,在定时器处理函数退出时,重新设置捕捉该信号。此处重新捕捉信号不需要重新设置setitimer函数。

2、当输入中断的字符为‘p’,暂停程序,内部实现为忽略定时器信号,当重新输入‘c’字符时,继续捕捉信号,程序继续运行。此时需要重新设置setitimer函数,否则定时器无法触发。

以上两种情况,同为先忽略定时器信号,再捕捉定时器信号,一种需要设置setitimer函数,一种则不需要设置。导致这种差异的原因是什么呢。

经过反复测试:在主函数中调用getitimer函数,获取定时器的值。

发现:

(定时器由it_value,it_interval两部分组成,it_value用于记录下次中断到来时间,随着时间减小;it_interval用于在it_value减为0时,重置it_value,记录两次中断之间的间隔)

当设置定时器后(设置it_value, it_interval),it_value将由指定值减为0,此时若信号为忽略,in_interval将不再继续重置it_value函数。此时it_value 为0, it_interval不为0。

此时定时器处于一种disable状态,但此disable状态与it_value 为0, it_interval为0的关闭状态并不是一个状态。(此处与定时器的manpage略有出入),disable状态不再触发定时器信号。

在上面的例子中,情况1,由于在中断处理函数中先屏蔽再捕捉,基本不会导致在此过程中it_value减为0,(时间太短,不过也有可能,极偶发事件,所以当重新设置捕捉信号时,it_value不是0, 当it_value再次为0时,信号将继续被捕捉,所以此时不需要设置setitimer函数。

情况2,当我们键入‘p’,忽略定时器中断,当我们在键入‘c’,由于键入的时间间隔较长,在这个过程中,定时器的it_value已经减为0,而当减为0时,信号为忽略状态,此时信号将继续处于disbale状态。之后再捕捉,由于定时器将保持disbale状态,将不会触发定时器信号,只有重新设置setitimer函数,重新打开定时器才能触发定时器中断。

以上结论均属于个人推测,未找到相关书籍证实,而且结论与定时器介绍略有偏差,所以还需进一步求证。

为保险起见,建议一旦先忽略,再捕捉定时器信号,均再次设置setitimer函数。

你可能感兴趣的:([待解决]重新捕捉定时器信号,是否需要再次调用setitimer函数)