我真的没有得到信号处理程序如何工作,特别是叉子。所以我需要做这个练习,但我无法正常工作。
我的主程序生成5个分叉,每个分叉只打印10个带有pid的消息。所以程序的目的,当我通过键盘发送SIGINT信号(Ctrl-c)它应该打印,“单个SIGINT到达”,如果两个SIGINT到达一秒之间,它应该打印“双SIGINT到达”并应该终止整个计划。因此,当我启动我的程序时,它会处理前两个SIGINT(我在第一个之后发送第二个超过1秒)但是它不会处理单个SIGINT而且也不会处理双重SIGINT。
所以我对信号非常困惑。福克斯继续加盖邮件。我将相同的处理程序加载到main和toks但是当我到达双SIGINT时我该怎么做才能终止所有的forc?我应该在处理程序中调用killl或其他函数来终止它们吗?
主要功能
/* libraries... */
volatile sig_atomic_t double_sigint = 0;
int64_t time_diff = 0;
int main()
{
int i;
int pid;
sigset_t set;
struct sigaction sa;
/* mask all signals */
/*H*/ if(sigfillset(&set) == -1 )
/*A*/ {perror("sigfillset"); exit(errno);}
/*N*/
/*D*/ if(sigprocmask(SIG_SETMASK,&set,NULL) == -1)
/*L*/ {perror("sigfillset"); exit(errno);}
/*E*/
/*R*/ memset(&sa,0,sizeof(sa));
/*B*/
/*L*/ sa.sa_handler = handler;
/*O*/
/*C*/ if(sigaction(SIGINT, &sa, NULL) == -1)
/*K*/ {perror("sigaction"); exit(errno);}
/**/
/**/ /* unmask all signals */
/**/ if( sigemptyset(&set) == -1 )
/**/ {perror("sigepmtyset"); exit(errno);}
/**/
/**/ if(sigprocmask(SIG_SETMASK,&set,NULL) == -1 )
/**/ {perror("sigprocmask"); exit(errno);}
for(i=0;i<5;++i)
{
if((pid = fork()) == -1)
{ perror("rec:fork"); exit(errno); }
if(pid == 0)/* figlio */
{
/* SAME HANDLER BLOCK IS HERE */
foo(i);
return;
}
sleep(1);
}
return 0;
}
foo功能
void foo(int i)
{
int k;
for(k=0; k<10; ++k)
{
printf("%d. fork %d. print\n", i, k);
sleep(1);
}
}
信号处理程序
void handler (int signum) {
struct timespec sig1;
struct timespec sig2;
if(double_sigint == 0)
{
if(clock_gettime(CLOCK_REALTIME, &sig1))
{ perror("failed to get sig1 time"); exit(errno); }
write(1,"Received single SIGINT\n",18);
double_sigint = 1;
}
else if(double_sigint == 1)
{
if(clock_gettime(CLOCK_REALTIME, &sig2))
{ perror("failed to get sig2 time"); exit(errno); }
time_diff = (sig2.tv_sec - sig1.tv_sec) + (sig2.tv_nsec - sig1.tv_nsec)/1000000000;
if(time_diff < 1)
{
double_sigint = 2;
write(1,"Received double SIGINT\n",18);
_exit(EXIT_FAILURE);
}
else
{
sig1.tv_sec = sig2.tv_sec;
sig1.tv_nsec = sig2.tv_nsec;
write(1,"Received single SIGINT\n",18);
}
}
}
答案 0 :(得分:0)
当您收到双重SIGINT时,只会使用行_exit(EXIT_FAILURE);
终止父进程。您之前创建的分叉未被杀死并继续运行,其父级现在是init进程。
如果您希望所有孩子都终止,您必须手动杀死他们。也许这篇文章会有所帮助:How to make child process die after parent exits
编辑:这不是问题,因为Ctrl + C会向所有孩子发送一个SIGINT(请参阅注释)。 对我有用的是:
while (1);
),因为一旦父进程终止,一些信号就不会被考虑在内。答案 1 :(得分:0)
在处理程序中,在else子句(double_sigint == 1)中,您要比较sig2和sig1,但sig1未初始化。当处理程序返回时,第一次调用处理程序时给出的值就消失了。您可以简单地为这些变量提供文件范围。
通过使用局部变量的未初始化值,您将获得未定义的行为。如果调用信号处理程序并且信号处理堆恰好处于上次调用时的状态,那么可能正常工作。例如,如果您发送信号两次而没有中间信号,就会发生这种情况。由于睡眠很可能是通过信号实现的,因此很可能自上一次调用以来sig1已经被修改,并且sig1不是您所期望的。然而,关于未定义行为的猜测有点毫无意义。