我有像这样的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
完成执行之前停止?
答案 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()
的第二次调用可能会彻底混淆。
因此,即使在单线程程序中,您也必须注意并非常小心如何修改全局变量。
但是,在单线程程序中,在处理信号时主循环不会有活动。实际上,即使在多线程程序中,接收(处理)信号的线程也会在信号处理程序运行时暂停,但其他线程不会被挂起,因此可能存在来自其他线程的并发活动。如果重要,请确保正确序列化对变量的访问。
另见: