我试图从网上找到的示例程序中了解信号在Linux中的工作方式,但是其中有些部分我并不太了解。
这是我的示例程序:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
void catcher(int sig) {
printf("catcher() has gained control\n");
}
int main(int argc, char *argv[]) {
struct sigaction sigact;
sigset_t sigset;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
sigaction(SIGUSR1, &sigact, NULL);
printf("before first kill()\n");
kill(getpid(), SIGUSR1);
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
sigprocmask(SIG_SETMASK, &sigset, NULL);
printf("before second kill()\n");
kill(getpid(), SIGUSR1);
printf("after second kill()\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是我的程序的示例输出:
在第一个kill()之前
catcher()
在第二个kill()
之后 获得了第二个kill()之前的控制权
我能知道为什么输出的第一行是before first kill()吗?为什么不catcher() has gained control首先出现?
据我所知,它sa_handler包括两种信号,信号默认值和信号忽略。
我们如何知道它将产生哪个信号?如果忽略信号,为什么会触发打印catcher()获得控制的函数?
此外,sa_mask该程序的功能是什么?以我的理解,sa_mask会阻塞指定的信号。
我能知道为什么输出中的第一行在第一个kill()之前吗?为什么catcher() has getting control没有首先出现?
您安装了一个捕获SIGUSR1. SIGUSR1在传递给进程之前,正常的程序执行流程一直在发生。所以在这里:
printf("before first kill()\n");
kill(getpid(), SIGUSR1);
Run Code Online (Sandbox Code Playgroud)
您仅在打印后生成信号before first kill()。你为什么不希望这会出现在之前catcher() has gained control呢?换句话说,当您调用 时printf("before first kill()\n");,尚未发出任何信号,因此您只能期望程序执行保持正常。
这行:
kill(getpid(), SIGUSR1);
Run Code Online (Sandbox Code Playgroud)
生成SIGUSR1. 操作系统在方便的时候将信号传递给进程。因为您安装了 的处理程序SIGUSR1,所以您的信号处理程序 ( catcher()) 被调用。您在打印第一行后发出信号,因此预计下一行输出将来自信号处理程序。
请注意,这printf(3)不是异步信号安全的,因此从技术上讲,您无法从信号处理程序内部调用它,但对于这些玩具示例来说通常没问题。
据我所知,sa_handler由两种类型的信号组成,信号默认和信号忽略。
还有更多的事情要做。的sa_handler字段struct sigaction可以具有值SIG_DFL,它对应于默认信号操作(默认操作在 中列出man signal),以及SIG_IGN,这意味着信号被忽略(引发信号时不会发生任何事情)。但sa_handler也可以是指向每次传递信号时要调用的函数的指针。这就是您显示的代码正在做的事情 - 它说:嘿,何时SIGUSR1交货,请致电catcher()。
我们如何知道它将产生哪个信号?如果信号忽略生成,为什么会触发函数打印 catcher() has Gained Control?
当您调用设置处理程序时,您指示了一个信号 ( SIGUSR1) 。sigaction(2)因此,交付catcher()时将被调用。SIGUSR1
另外,这个程序中的sa_mask函数是什么?根据我的理解,sa_mask会阻塞指定的信号。
它是一个信号掩码,在进入信号处理程序时自动安装,并在信号处理程序返回时卸载。默认情况下,即使您向其传递一个空掩码,被捕获的信号在进入处理程序时也始终会被阻止(除非在字段SA_NODEFER中设置了标志)。但是,您可能希望在处理程序执行时阻止其他信号 - 这样做的方法是在.sa_flagsstruct sigactionsa_mask