Linux下C语言的信号处理

5

我正在尝试从网上找到的示例程序中理解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;
}

这是程序输出的样本:

在第一个kill()之前
catcher() 已获取控制权
在第二个kill()之前
在第二个kill()之后

我能知道为什么输出中第一行是before first kill()吗?为什么不是catcher() has gained control先出现?

据我所知,sa_handler由两种类型的信号组成,即默认信号和忽略信号。

我们如何知道它将生成哪个信号?如果生成忽略信号,为什么会触发函数打印catcher() has gained control?

此外,这个程序中的sa_mask函数是什么?据我理解,sa_mask会阻塞指定的信号。


注意:不要在信号处理程序中使用printf()和相关函数。这是不安全的。 - wildplasser
1个回答

1

我能知道为什么输出的第一行在第一个kill()之前吗?为什么catcher()的控制权没有首先出现?

您安装了一个信号处理程序来捕获 SIGUSR1。 在 SIGUSR1 传递给进程之前,正常的程序执行流程会继续进行。 因此,在这里:

printf("before first kill()\n");
kill(getpid(), SIGUSR1);

你只有在打印before first kill()之后才会生成信号。为什么你不希望它出现在catcher() has gained control之前呢?换句话说,当你调用printf("before first kill()\n");时,还没有引发任何信号,所以你只能期望程序执行保持正常。
这一行:
kill(getpid(), SIGUSR1);

生成SIGUSR1信号。操作系统在方便的时候将信号传递给进程。因为您为SIGUSR1安装了处理程序,所以将调用您的信号处理程序(catcher())。在打印第一行后,您引发信号,因此可以预期下一行输出将来自信号处理程序。
请注意,printf(3)不是异步信号安全的,因此从信号处理程序内部调用它在技术上是不允许的,但对于这些玩具示例通常是可以的。

据我所知,sa_handler包含两种类型的信号,信号默认和信号忽略。

除此之外还有更多。 struct sigactionsa_handler字段可以具有值SIG_DFL,它对应于默认信号操作(默认操作在man signal中列出),以及SIG_IGN,这意味着信号被忽略时什么都不会发生。但是,sa_handler也可以是指向您希望在每次传递信号时调用的函数的指针。这就是您展示的代码所做的-它正在说:嘿,当发送SIGUSR1时,请调用catcher()

我们如何知道它将生成哪个信号?如果忽略生成信号,为什么会触发打印catcher()的函数?

在调用sigaction(2)设置处理程序时,您指定了一个信号(SIGUSR1)。因此,当传递SIGUSR1时,将调用catcher()

此外,在这个程序中,sa_mask函数是什么?在我的理解中,sa_mask将会阻塞指定的信号。 这是一个信号掩码,在进入信号处理程序时自动安装,并在信号处理程序返回时卸载。默认情况下,即使您传递了一个空掩码,被捕获的信号在进入处理程序时始终被阻止(除非在struct sigaction的sa_flags字段中设置了SA_NODEFER标志)。但是,您可能希望在处理程序执行时阻止其他信号-这样做的方法是在sa_mask中指示这些信号。

1
@doe,它用于标记问题的答案,并使用答案勾选标记,以便回答者可以通过他的工作获得一些声望。 - Luis Colorado

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接