是否有必要调用另一个setitimer函数,当我第一次忽略警报信号然后捕获它时

时间:2015-07-12 13:13:36

标签: c linux signals

我在这两种情况下迷失了,但我无法找出它们之间的区别。我想在代码开头捕获警报信号,因此我调用了settimer函数和signal(SIGALRM, move_),程序运行正常。

在信号处理函数中,我首先忽略了信号,在返回之前我调用了信号(SIGALRM,move_),并且程序再次捕获了信号。

注意,在这种情况下,我没有必要再次调用setitimer,程序可以捕获警报信号

另一种情况,在SIGIO处理程序中,我输入'p',并且忽略了警报信号。然后我键入'c',我想让程序再次收到警报。

请注意,但此时,我必须再次调用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;
}

根据来自@ user3629249的adivce,我修改了我的代码,除了标签并在信号处理程序中显示。

@Oldest Software Guy建议使用sigaction,但在这种情况下信号和sigaction似乎是相同的。为简单起见,我也使用信号。

为了解决我的疑问,我通过修改代码中的细节来以多种方式测试我的代码。我观察它们的外观并得出结论,这似乎是可以接受和合理的。我试图找到一些有用的信息关于计时器细节以支持我的意见,但我失败了。

以下是我的程序。

如果我在代码的开头设置了setitimer和signal(SIGALRM,SIG_IGN),在while循环中调用getitimer,则it_interval不为0,但it_value总是为0,换句话说,it_interval不会重置it_value。

在我的代码中的move_函数中,我首先在返回之前发信号(SIGALRM,SIG_IGN)和信号(SIGALRM,move_),信号将像往常一样出现。但是当我删除信号(SIGALRM,move_)之后, it_value递减为0,it_interval不会重置it_value。另一方面,如果我不删除信号(SIGALRM,move_),那时it_value递减到0,警报信号的状态被捕获,因此it_interval将重置it_value并且程序运行良好。使用getitimer可以发现这种现象。

以下是我的结论。

我调用setitimer,定时器开始。当it_value每次递减为0时,定时器将检查信号是否有捕获。如果没有,定时器禁用(it_interval不会永远重置it_value) 。如果我想在定时器禁用后再次捕获信号,我需要再次调用setitimer。此时,定时器仍然存在,但状态为禁用。(这种禁用不等于禁用的类型,it_value是0和it_interval是0)

但是在it_value的窗口不是0,我改变捕获信号,我不需要再次调用setitimer。

考虑到可靠性,我最好在重置信号之前调用setitimer。

结论似乎很奇怪,如果你有兴趣的话,自己测试一下。

0 个答案:

没有答案