信号执行期间的 SIGProc掩码

sigprocmask during signal's execution

本文关键字:SIGProc 掩码 执行期 信号      更新时间:2023-10-16

我目前正在研究使用sigprocmask来阻止某些信号(在这种情况下,SIGALRMSIGCHLD),当代码的关键段正在执行。与这些信号相关联的两个信号处理程序都将访问和修改中心数据结构,因此,在主进程对其进行处理时,防止它们访问它是至关重要的。

目前,我的计划是在代码的关键部分开始时简单地禁用这些信号,然后在结束时重新启用它们。

void criticalFunction(void) {
    // disable signals with sigprocmask
    // critical code
    // enable signals with sigprocmask
}

然而,用于将被阻塞的信号的信号处理程序也调用criticalFunction。当它们调用sigprocmask函数并对自己的信号启用阻塞时,会发生什么?他们会拖延还是继续执行?(或者第三个条件…)

我能找到的唯一注释是:

如果在信号处理程序中调用sigprocmask(),则从处理程序可以通过恢复原始状态来撤销sigprocmask()的工作等待的信号掩码。(http://www.mkssoftware.com/docs/man3/sigprocmask.3.asp)

(这是我上一个问题的后续问题:信号处理程序访问队列数据结构(竞争条件?))

请记住,信号处理程序内部的默认行为是阻塞正在处理的信号。此外,在信号处理程序内部进行函数调用时,您希望只调用信号安全的函数。话虽如此,sigprocmask()是一个信号安全的函数,如果你用它来阻止被信号处理程序阻塞的相同的信号,它被内部调用,那么真的什么都不会发生…您将继续使用当前的信号掩码。唯一的区别是,在信号处理程序中,只有SIGALRMSIGCHLD的信号保证被阻塞(这取决于您在哪个信号处理程序中),而当您调用sigprocmask()来阻塞这些特定的信号时,调用后两个信号都将被阻塞。

要注意的是criticalFunction代码的第二部分,当您尝试调用sigprocmask()启用当前在信号掩码中被阻塞的信号时。这可能会造成这样一种情况:在对信号处理程序的调用中,最终会出现一定程度的可重入性。换句话说,为您所在的信号处理程序启用信号可能意味着在退出当前信号处理程序之前,另一个SIGALRMSIGCHLD被捕获,您将再次重新进入信号处理程序来处理这个新捕获的信号。只要你在任何关键部分更新后启用信号,那么我认为你应该对这种重新进入的情况很好,但只是为了安全起见,你可能只想在criticalFunction的最后启用criticalFunction中的信号,而不是在中间的某个地方,当你从criticalFunction返回时,不要做任何不会异步安全的事情……你必须假设第二个sigprocmask()返回后的任何代码都可能没有按顺序执行(即,它可能在第二个信号被捕获并运行其信号处理程序之后执行)。

如果你试图调用exec家族的东西,或者你的信号处理程序内部的东西,你只需要担心"拖延"。新覆盖的进程将继承当前进程的信号掩码,所以如果当前进程阻塞了某些信号,那么它们也会在新进程中被阻塞。因此,如果新进程假定信号已解除阻塞,则新进程中的信号处理程序将永远不会运行。

BTW,一个警告:不要混淆信号和线程!你在问题中提到了"main process"…我希望这并不意味着你试图混淆信号和线索。如果是这样,那就需要一个非常具体的习语,否则会造成各种各样的混乱。

你的设计是错误的,当你说"信号处理程序[…]]调用criticalFunction ."信号处理程序不应该做任何大量的工作。

在信号处理程序中,唯一合理的做法是修改sigatomic_t类型的变量。这通常用于设置标志,其余的代码(例如主循环)只需要定期检查是否设置了任何标志。

我认为它实际上是未定义的行为如果一个信号处理程序做任何其他的。Update: From man 2 signal: "参见signal(7),可以从信号处理程序内部安全地调用异步信号安全函数的列表。"