C 当我第一次忽略报警信号,然后捕捉到它时,是否需要调用另一个setitimer函数

C 当我第一次忽略报警信号,然后捕捉到它时,是否需要调用另一个setitimer函数,c,linux,signals,C,Linux,Signals,我在这两种情况下迷失了方向,但我找不出它们之间的区别。我想在代码开始时捕捉报警信号,因此我调用了settimer函数和信号(SIGALRM,move),程序工作正常 有一种情况是,在信号处理器函数中,我首先忽略了信号,在返回之前我调用了信号(SIGALRM,move_),程序再次捕获了信号 注意,在这种情况下,我没有必要再次调用setitimer,程序可以捕捉报警信号 另一种情况是,在SIGIO处理程序中,我输入了'p',报警信号被忽略。然后我输入“c”,我想让程序再次捕捉警报 注意,但此时,如

我在这两种情况下迷失了方向,但我找不出它们之间的区别。我想在代码开始时捕捉报警信号,因此我调用了
settimer
函数和
信号(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;
}
#包括
#包括
#包括
#包括
#包括
#定义MESG“xxxxxxx”
#定义空白“”
#定义柱100
int设置计时器(int);
无效移动(int);
无效键盘(int);
int x=80;
int y=0;
int dir=-1;
int-ppp=0;
内部主(空)
{
int标志;
结构itimerval old;
initscr();
crmode();
noecho();
清除();
信号(SIGIO,键盘);
fcntl(0,F_SETOWN,getpid());
flag=fcntl(0,F_GETFL);
fcntl(0,F|u SETFL,(标志为O|u异步));
信号机(信号机,移动);
设定计时器(150);
mvaddstr(y,x,MESG);
刷新();
而(1){
睡眠(1);
getitimer(ITIMER\u 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);
如果(ppp==1){
信号(信号灯、信号灯);
购买力平价=0;
}
如果(购买力平价=2){
设定计时器(150);
信号机(信号机,移动);
购买力平价=0;
}
}
endwin();
}
int settimer(int毫秒)
{
结构时间;
长秒,usec;
秒=毫秒/1000;
usec=(毫秒%1000)*1000L;
时间_val.it _interval.tv _sec=秒;
time_val.it_interval.tv_usec=usec;
时间值it值tv秒=秒;
时间_val.it _value.tv_usec=usec;
返回setitimer(ITIMER\u REAL和time\u val,NULL);
}   
无效移动(内部符号)
{
信号(信号灯、信号灯);
mvaddstr(y,x,空白);
if(dir==1&&y==0)
dir=1;
if(dir==1&&y==line-1)
dir=-1;
y+=dir;
mvaddstr(y,x,MESG);
刷新();
信号机(信号机,移动);
}
无效键盘(整数符号)
{
INTC;
c=getch();
如果(c='')
dir=-dir;
如果(c=='p')
购买力平价=1;
如果(c=='c')
购买力平价=2;
}
根据@user3629249的adivce,我修改了我的代码,除了标签和显示在信号处理程序中

@最老的软件人建议使用sigaction,但在这种情况下signal和sigaction似乎是一样的。为了简单起见,我还使用了signal

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

下面是我的程序

如果我在代码开始时设置ITIMER和信号(SIGALRM,SIG_IGN),在while循环中调用getitimer,it_间隔不是0,但it_值始终是0,换句话说,it_间隔不会重置it_值

在我的代码中的move_函数中,在返回之前,我首先发送信号(SIGALRM,SIG_IGN)和信号(SIGALRM,move_),信号会像往常一样出现。但是当我删除信号(SIGALRM,move_)时,在最后一个it_值减为0后,it_间隔不会重置it_值。另一方面,如果我不删除信号(SIGALRM,move_),此时it_值将减小到0,报警信号的状态将被捕获,因此it_间隔将重置it_值,程序工作正常。使用getitimer可以发现这种现象

以下是我的结论

我调用setitimer,计时器开始计时。每次it_值递减到0时,计时器将检查信号是否有捕捉。如果没有,计时器将禁用(it_间隔不会永远重置it_值)。如果我想在定时器禁用后再次捕获信号,我需要再次调用setitimer。此时,定时器仍然存在,但状态为disable。(这种禁用不等于disable,它的值为0,它的间隔为0)

但是在它的窗口,值不是0,我改变捕捉信号的方式,我不需要再次调用setitimer

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


结论似乎很奇怪,如果你对它感兴趣,就自己测试它。

代码中的一些注释:1)main只有3种有效格式,所有格式都有“int”返回类型,从不使用“void”2)为了便于我们人类阅读,缩进代码,从不使用制表符缩进,建议使用4个空格。3) 为了便于我们阅读,在函数之间和代码块之间插入一条空行。4)对于变量名使用“Neo”是一个非常坏的想法,因为它是C++中的保留字。更多注释:信号处理程序函数不应该操纵显示,而是它可能设置一个主程序循环可以检查并动作的标志。在GCC/Ubuntu下编译所发布的代码会引发需要固定的10个警告。建议在编译时,始终启用所有警告,然后修复这些警告。(例如,在信号处理程序例程中,带有back tics的文本不是有效的注释。请使用/*…*/)1),只需为要解释的主代码设置一个标志即可。调用libc函数是一个难题。2)使用Berkeley signal(3)包编写正确的程序是不可能的;它根本上是有缺陷的。而是使用AT&T sigaction接口。伯克利体系结构具有无法避免的内在竞争条件;