我正在试验 Unix 中提供的信号。我现在关注的两个是 Ctrl + C 和 Ctrl + Z 。我想抓住信号,并在屏幕上显示一条消息。我得到了大部分工作。就像按下任一信号时显示的消息一样。但它似乎只能工作一次。我希望每次按 Ctrl + C 或 Ctrl + Z 时显示消息。像一个循环。
#include <stdio.h>
#include <signal.h>
void handler (int signal);
int main ()
{
if (signal(SIGINT, handler) == SIG_ERR)
{
write (2, "Error catching signal C \n",26);
}
if (signal(SIGTSTP, handler) == SIG_ERR)
{
write(2, "Error catching signal Z \n", 26);
}
pause();
}
void handler (int signal)
{
if (signal == SIGINT)
{
write(1, "CONTROLC \n", 11);
}
else if (signal == SIGTSTP)
{
write(1, "CONTROLZ \n", 11);
}
else
{
write(2, "error \n", 8);
}
main();
}
我试图使用main函数,以便它可以重新启动程序,但我假设它在一个信号中调用main,所以它的行为有所不同?
答案 0 :(得分:3)
哇,不要这样做。 :)
这里发生的事情是,例如,在执行处理程序期间屏蔽(阻止)SIGINT。因此,从处理程序中重新调用main
重新运行main
并阻止SIGINT。因此,您会看到您的处理程序每个信号只触发一次 - 它在之后被阻止。 (请注意,signal
保证此阻止行为不,这是should use sigaction
instead的一个原因。)
典型的信号处理程序应尽可能少地工作,仅使用async-signal-safe函数(如果有的话)。将处理程序视为流程的普通流程的中断,这是一个特殊的异步流程,如果需要,可以use its own stack。
如果您希望程序的行为类似于循环,请将其编码为循环:
static volatile sig_atomic_t flag_int;
static volatile sig_atomic_t flag_tstp;
static void handle_int(int s) { flag_int = 1; } /* register me with sigaction */
static void handle_tstp(int s) { flag_tstp = 1; } /* me, too */
...
while (1) {
pause();
if (flag_int) { printf("CONTROL C\n"); flag_int = 0; }
if (flag_tstp) { printf("CONTROL Z\n"); flag_tstp = 0; }
}
答案 1 :(得分:1)
不要从信号处理程序中调用main(),因为您的程序现在卡在信号处理程序中,并且在处理程序运行时它不会再次为同一信号调用另一个信号处理程序。 (如果使用sigaction()而不是signal(),则可以更改该行为。
另请参阅pause()调用的内容。
<强>描述强> pause()使调用进程(或线程)进入休眠状态,直到传递一个终止进程或导致进程的信号 调用信号捕捉功能。
所以,你的暂停();呼叫等待直到发送信号,然后继续您的程序。
所以,例如,做这样可以让你的程序继续运行。
for(;;) {
pause();
}
答案 2 :(得分:0)
请勿使用信号(2),除非可能将给定信号的处置设置为SIG_DFL
或SIG_IGN
。它的行为因Unix而异。
为了便于移植(在POSIX系统中)和更好的控制,您应该通过 sigaction (2)系统调用来安装用户信号处理程序。除此之外,还允许您在安装处理程序时在单次模式和持久模式之间进行选择。
如果您有义务使用信号(2),那么最好的办法就是让处理程序做的最后一件事就是重新安装自己作为给定信号的处理程序(当时#39)事实上你想要的是什么。