C 如何避免信号处理器中的竞争条件
我正在从事一个涉及信号驱动I/O的项目,该项目最终可能会使用使用sigaction()创建的信号处理程序。我担心处理程序可能会被调用多次。换句话说,当它被消息B中断并开始处理B时,它将处理消息A,这可能会导致问题。我在网上看到一些代码使用sigprocmask来避免这种情况,但我觉得这是错误的。例如:C 如何避免信号处理器中的竞争条件,c,concurrency,signals,race-condition,C,Concurrency,Signals,Race Condition,我正在从事一个涉及信号驱动I/O的项目,该项目最终可能会使用使用sigaction()创建的信号处理程序。我担心处理程序可能会被调用多次。换句话说,当它被消息B中断并开始处理B时,它将处理消息A,这可能会导致问题。我在网上看到一些代码使用sigprocmask来避免这种情况,但我觉得这是错误的。例如: void handle_signal(int sig_num) { sigset_t mask_set; /* used to set a signal masking set. */
void handle_signal(int sig_num)
{
sigset_t mask_set; /* used to set a signal masking set. */
sigset_t old_set; /* used to store the old mask set. */
/* re-set the signal handler again to catch_int, for next time */
signal(SIGINT, catch_int);
/* mask any further signals while we're inside the handler. */
sigfillset(&mask_set);
sigprocmask(SIG_SETMASK, &mask_set, &old_set);
.... (content handling code here) ....
/* restore the old signal mask */{{/COMMENT_FONT}*/
sigprocmask(SIG_SETMASK, &old_set, NULL);
}
这显然是错误的,因为sigprocmask不是信号的原子。换句话说,在调用信号处理程序和调用sigprocmask之间有一个时间窗口,可以在该窗口中第二次或第三次调用信号处理程序,从而创建竞争条件
我的选择:
(1) 使用处理程序内部的信号量将处理程序的任何冗余调用排队
(2) 将处理程序编写为可重入程序,因此可以同时多次调用它
(3) 还有别的解决办法吗
如果我选择上面的选项(2),我能认为套接字读队列是线程安全的吗?例如,假设套接字处理程序被调用两次。实例A开始从套接字读取数据,然后中断,实例B开始读取数据包。这是否会导致A发现队列为空并结束,或者我将面临某种错误的风险?
如果您正在使用sigaction
设置信号处理程序,则导致触发处理程序的信号默认情况下已在处理程序内被阻止
在您的代码中,所有信号的阻塞和旧掩码的恢复都是关于阻塞所有其他信号,原始信号(触发处理程序)将被阻塞,直到您从处理程序返回(或者您明确地取消阻塞)
使用sigaction
可以通过设置struct sigaction
的sa_mask
字段来避免执行此块并在处理程序中还原,该字段是处理程序中阻止的信号集
此外,您使用signal
来“重新设置”处理程序有点混乱,您调用函数handle\u signal
,然后重新设置为catch\u int
(假设此处理程序实际处理SIGINT
)
每次触发处理程序时,旧的signal
API确实用于将信号处理程序重置回默认值。但是,默认情况下sigaction
不执行此操作,因此您不需要“重新设置”如果您使用的是sigaction
API,则使用信号处理程序。我个人会避免在同一个程序中混合调用signal
和sigaction
,我会选择一个并坚持使用它
总之,我认为您对
sigprocmask
不具有原子性的担忧是不必要的,因为所讨论的信号已经被阻止,您对signal
和sigaction
的混合使用更让我担心。您的意思是sigaction()
用于设置信号处理程序?我找不到关于sigact()的任何信息
在快速搜索之后。@Andrew是的,我修复了输入错误使用sigaction
而不是signal
,您将能够保护您的处理程序不被您想要的任何其他信号打断。这不是我的代码,这是我认为错误的一个示例。好的。希望答案能够解释您的担忧是不必要的。我会ecommendsigaction
如果该API对您可用,请阅读sigaction
手册,该手册将提供更多详细信息。如果可以使用sigprocmask()
etc,sigaction()
也可以,而我可以想象使用sigaction()
和无sigprocmask()
(从上世纪90年代早期的一个实现,也许),你不太可能找到<代码> SIGPROMASK()/<代码>,没有<代码> SIGATAON()/<代码>;所以我不太可能认为它是“不可能的”,并且不担心可能。