信号执行期间的sigprocmask

我正在研究使用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()来阻止那些信号处理程序时特定信号,两个信号将在通话后被阻止。

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

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

BTW,一个警告: 不要混合信号和线程 ! 你在问题中提到“主要过程”……我希望这并不意味着你试图混合信号和线程。 如果是这样,那需要一个非常具体的习语,否则你将创造各种各样的破坏。

当你说“信号处理程序调用criticalFunction ”时,你的设计是错误的。 信号处理人员不应该做任何大量的工作。 他们不是为此而做的。

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

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