3

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

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

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

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

4

2 回答 2

4

请记住,信号处理程序内部的默认行为是阻止正在处理的信号。此外,在信号处理程序内部进行函数调用时,您只想调用信号安全函数。话虽如此,sigprocmask()是一个信号安全函数,如果您使用它来阻止被信号处理程序阻止的同一信号,则它在内部被调用,那么实际上什么都不会发生……您将保持与您当前拥有的相同信号掩码。唯一的区别是在信号处理程序内部,只有信号SIGALRM或信号SIGCHLD被保证被阻止(这取决于您所在的信号处理程序),当您调用sigprocmask()阻止这些特定信号时,两个信号通话后会被屏蔽。

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

exec如果您尝试从家庭中调用某些东西,或者在您的信号处理程序内部调用某种性质的东西,您只需要担心“拖延” 。会发生的情况是,新覆盖的进程将从当前进程继承信号掩码,因此如果当前进程阻塞了某些信号,那么它们也会在新进程中被阻塞。因此,如果新进程假设信号未被阻塞,则新进程中的信号处理程序将永远不会运行。

顺便说一句,一个警告:不要混合信号和线程!您在问题中提到了“主进程”......我希望这并不意味着您正在尝试混合信号和线程。如果是这样,那需要一个非常具体的成语,否则您将造成各种破坏。

于 2011-11-17T01:38:05.570 回答
2

当您说“信号处理程序 [...] 调用criticalFunction”时,您的设计是错误的。信号处理程序永远不应该做任何大量的工作。他们不是为此而生的。

您应该在信号处理程序中合理地做的唯一一件事是修改 type 的变量sigatomic_t。这通常用于设置标志,您的代码的其余部分(例如主循环)只需定期检查是否设置了任何标志。

我认为如果信号处理程序执行除此之外的任何操作,这实际上是未定义的行为。更新:来自man 2 signal:“请参阅signal(7)可以从信号处理程序内部安全调用的异步信号安全函数列表。”

于 2011-11-17T01:12:11.490 回答