当我用信号(SIGINT,f)捕获信号时,是否并行执行?

时间:2014-06-05 14:35:58

标签: c signals

我有像这样的C代码

#include <stdio.h>
#include <unistd.h>
#include <signal.h>


void handler_function(int);
int i=0;
int j=0;
int main() {
    signal(SIGINT,f);
    while(1) {
     /* do something in variable `i` */
    }
}

void f(int signum) {
     /* do something else on variable `i` */
}

它可以产生数据竞争吗?即f并行执行(即使在多线程机器中)到main。或者main可能会在f完成执行之前停止?

2 个答案:

答案 0 :(得分:2)

首先根据signal()的手册页,您不应该使用signal(),而是sigaction()

  

signal()的行为在UNIX版本中各不相同,并且在不同版本的Linux上也有不同的历史变化。避免使用:改为使用sigaction(2)。请参阅下面的便携性。

但有人可能希望signal()表现得很清醒。但是,可能存在数据竞争,因为main可能在商店之前被中断,例如在这样的情况下

if ( i > 10 ) { 
    i += j; 
}
void f(int signum) {
    i = 0;
}

如果main超过比较(或者如果main在比较时被中断,则相应的注册表不会更新),main仍然会i += j数据竞赛。

那么这又给我们留下了什么? - 如果不能保证信号处理程序不能中断此操作(例如,禁用某些操作的信号处理程序),就不要修改在信号处理程序的其他地方修改的全局变量。

答案 1 :(得分:1)

除非您使用标准C中的raise()kill()getpid()的值作为PID参数,否则信号事件将是异步的。

在多核机器上的单线程代码中,这意味着您无法分辨“做变量i&#39;做什么”。码。例如,该代码可能刚刚从i获取了值并使其递增,但尚未保存递增的值。如果信号处理函数f()读取i,以不同的方式修改它,保存结果并返回,原始代码现在可以写入递增的值i而不是使用该值由f()修改。

这导致了对信号处理程序中可以执行的操作的许多限制。例如,在信号处理程序中调用printf()是不安全的,因为它可能需要进行内存分配(malloc()),但在malloc()修改其链接时信号可能已到达可用内存列表。对malloc()的第二次调用可能会彻底混淆。

因此,即使在单线程程序中,您也必须注意并非常小心如何修改全局变量。

但是,在单线程程序中,在处理信号时主循环不会有活动。实际上,即使在多线程程序中,接收(处理)信号的线程也会在信号处理程序运行时暂停,但其他线程不会被挂起,因此可能存在来自其他线程的并发活动。如果重要,请确保正确序列化对变量的访问。

另见: