sig_atomic_t实际上如何工作?

时间:2014-07-24 10:39:26

标签: c linux signals

编译器或操作系统如何区分sig_atomic_t类型和普通的int类型变量,并确保操作是原子的?使用两者的程序具有相同的汇编代码。如何特别注意使操作成为原子?

5 个答案:

答案 0 :(得分:19)

sig_atomic_t不是原子数据类型。它只是您可以在信号处理程序的上下文中使用的数据类型,即全部。因此,最好将名称读作“相对于信号处理的原子”。

为了保证与信号处理程序之间的通信,只需要原子数据类型的一个属性,即读取和更新将始终看到一致的值。其他数据类型(例如可能long long)可以用较低和较高部分的几个汇编指令编写,例如:保证sig_atomic_t可以一次性读写。

因此,平台可以选择任何整数基类型为sig_atomic_t,以保证volatile sig_atomic_t可以安全地用于信号处理程序。许多平台为此选择了int,因为他们知道对于他们int只用一条指令编写。

最新的C标准C11具有原子类型,但它们完全不同。其中一些(那些“无锁”)也可能用于信号处理程序,但这又是一个完全不同的故事。

答案 1 :(得分:10)

请注意,sig_atomic_t不是线程安全的,只是异步信号安全。

原子论涉及两种障碍:

  1. 编译器障碍。它确保编译器不会对读取/写入其他变量的原子变量重新排序读取/写入。这是volatile关键字的作用。
  2. CPU障碍和可见性。它确保CPU不会重新排序读取和写入。在x86上,对齐1,2,4,8字节存储的所有加载和存储都是原子的。可见性可确保商店对其他线程可见。同样,在Intel CPU上,由于cache coherence and memory coherence protocol MESI,商店可以立即显示给其他线程。但这可能会在未来发生变化。有关详细信息,请参阅英特尔®64和IA-32架构软件开发人员手册第3A卷中的§8.1锁定原子操作。
  3. 对主题观察atomic Weapons: The C++ Memory Model and Modern Hardware进行全面处理。

答案 2 :(得分:7)

sig_atomic_t通常只是typedef(对某些系统特定的整数类型,通常为intlong)。使用volatile sig_atomic_t(不仅仅是sig_atomic_t)非常重要。

当您添加volatile关键字时,编译器必须避免大量优化。

最近的C11标准添加了_Atomic<stdatomic.h>。您需要最近的GCC(例如4.9)来支持它。

答案 3 :(得分:0)

  

使用两者的程序具有相同的汇编程序代码。如何特别注意使操作成为原子?

虽然这是一个老问题,但我认为仍然值得专门解决这部分问题。在Linux上,sig_atomic_t由glibc提供。 glibc中的sig_atomic_tint的typedef,没有特殊处理(截至本文)。 glibc docs解决了这个问题:

  

在实践中,您可以假设int是原子的。你也可以假设   指针类型是原子的;这很方便。这两个   在GNU C库的所有机器上都有假设   支持我们所知道的所有POSIX系统。

换句话说,只有普通int已经满足glibc支持的所有平台上sig_atomic_t的要求,并且不需要特殊支持。尽管如此,C和POSIX标准要求sig_atomic_t因为可能有一些奇特的机器,我们要在其上实现C {和} int不满足sig_atomic_t的要求。

答案 4 :(得分:0)

此数据类型似乎是原子的。 从这里:https://www.gnu.org/software/libc/manual/html_node/Atomic-Types.html

  

24.4.7.2原子类型为了避免不确定中断变量的访问,可以使用特定的数据类型进行访问   总是原子的:sig_atomic_t。读取和写入此数据类型是   保证只在一条指令中发生,所以没有办法   处理程序以在访问“中间”运行。

     

类型sig_atomic_t始终是整数数据类型,但它是哪一个   的大小以及其中包含的位数可能会因计算机而异。

     

数据类型:sig_atomic_t这是整数数据类型。这个的对象   类型始终是原子访问的。

     

在实践中,您可以假定int是原子的。你也可以假设   指针类型是原子的;那很方便。这两个   假设在GNU C库的所有机器上都是正确的   支持我们所知道的所有POSIX系统。