我在这两种情况下迷失了,但我无法找出它们之间的区别。我想在代码开头捕获警报信号,因此我调用了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。
结论似乎很奇怪,如果你有兴趣的话,自己测试一下。