sigaction和signal有什么区别?

我正要为我们在这里的应用程序添加一个额外的信号处理程序,并且我注意到作者使用了sigaction来设置其他信号处理程序。 我打算使用信号。 遵循约定,我应该使用sigaction,但是如果我是从头开始写的,应该select哪一个?

使用sigaction()除非你有非常令人信服的理由不这样做。

signal()接口具有古代性(因此可用),并且在C标准中定义。 尽pipe如此, sigaction()避免了一些不受欢迎的特性 – 除非使用显式添加到sigaction()的标志来忠实地模拟旧的signal()行为。

  1. 在当前处理程序执行时, signal()函数不会(必然)阻止其他信号到达; sigaction()可以阻止其他信号,直到当前处理程序返回。
  2. signal()函数(通常)会将信号操作重置为几乎所有信号的SIG_DFL (默认值)。 这意味着signal()处理程序必须重新安装自己作为其第一个操作。 它还会在信号被检测到和处理程序重新安装期间打开一个漏洞窗口,在此期间,如果信号的第二个实例到达,默认行为(通常会终止,有时会带有偏见 – 又名核心转储)。
  3. signal()的确切行为因系统而异 – 标准允许这些变化。

这些通常是使用sigaction()而不是signal()好理由。 但是, sigaction()的接口不可否认更加复杂。

无论使用哪种方法,都不要被sighold()sigignore()sigpause()sigrelse()等替代信号接口所诱惑。 它们名义上是sigaction()替代品,但是它们只是几乎没有标准化,并且出现在POSIX中用于向后兼容而不是严格使用。 请注意POSIX标准说他们在multithreading程序中的行为是不确定的。

multithreading程序和信号是另外一个复杂的故事。 AFAIK, signal()sigaction()在multithreading应用程序中都可以。

Cornstalks 观察到 :

signal()的Linux手册页说:

   signal()在multithreading过程中的影响是未指定的。

因此,我认为sigaction()是唯一可以在multithreading进程中安全使用的。

那很有意思。 在这种情况下,Linux手册页比POSIX更具限制性。 POSIX指定signal()

如果进程是multithreading的,或者进程是单线程的,并且执行信号处理程序的结果不是如此:

  • 调用abort()raise()kill()pthread_kill()sigqueue()来产生一个没有被阻塞的信号
  • 待解决的信号被解除阻塞并在解除阻塞的呼叫返回之前被传递

如果信号处理程序引用了具有静态存储持续时间的errno以外的任何对象,而不是通过为声明为volatile sig_atomic_t的对象volatile sig_atomic_t ,或者信号处理程序调用了本标准中定义的任何函数Signal Concepts中列出的函数。

所以POSIX明确指出了multithreading应用程序中signal()的行为。

尽pipe如此, sigaction()在所有情况下都是首选的 – 可移植的multithreading代码应该使用sigaction()除非有一个压倒性的原因,为什么它不能(比如“只使用标准C定义的函数” – 是,C11代码可以是multithreading的)。 基本上这个答案的开头段落也是这样说的。

它们是操作系统信号设施的不同接口。 如果可能的话,应该更喜欢使用sigaction来发信号,因为signal()具有实现定义的(通常是竞态容易的)行为,并且在Windows,OS X,Linux和其他UNIX系统上的行为不同。

有关详情,请参阅此安全说明 。

对我来说,这下面的线足以决定:

sigaction()函数为控制信号提供了更加全面和可靠的机制。 新的应用程序应该使用sigaction()而不是signal()

http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html#tag_03_690_07

无论您是从头开始还是修改旧程序,sigaction都应该是正确的select。

signal(3)手册页:

描述

  This signal() facility is a simplified interface to the more general sigaction(2) facility. 

两者都调用相同的基础设施。 你大概不应该用两个操纵单个信号的反应,但是混合它们不应该导致任何事情的破坏。

我会使用signal(),因为它至less在理论上更便携。 我会投票任何评论人谁可以想出一个现代系统,没有一个POSIX兼容层,并支持信号()。

从GLIBC文件引用:

在单个程序中可以同时使用signal和sigaction函数,但是你必须小心,因为它们可以以一种奇怪的方式进行交互。

sigaction函数指定比signal函数更多的信息,所以signal的返回值不能表示sigaction的全部可能性。 因此,如果您使用信号保存并稍后重新build立操作,则可能无法正确重新build立使用sigactionbuild立的处理程序。

为避免出现问题,如果程序使用了sigaction,则始终使用sigaction来保存和恢复处理程序。 由于sigaction更一般,它可以正确地保存和重新build立任何动作,而不pipe它是最初是用signal还是sigactionbuild立的。

在一些系统上,如果你用信号build立一个动作,然后用sigaction检查它,你得到的处理程序地址可能与你用信号指定的地址不一样。 它甚至可能不适合用作带有信号的动作参数。 但是你可以依靠它作为sigaction的一个参数。 这个问题从来没有发生在GNU系统上。

所以,你最好在一个程序中使用一个或另一个机制。

可移植性注意:基本信号函数是ISO C的一个特性,而sigaction是POSIX.1标准的一部分。 如果您担心可移植到非POSIX系统,那么您应该使用信号function。

Copyright(C)1996-2008 Free Software Foundation,Inc.

根据自由软件基金会发布的GNU自由文档许可证版本1.2或任何更高版本的条款,允许复制,分发和/或修改本文档; 没有不变部分,没有封面文本,也没有封底文本。 “GNU自由文档许可证”一节中包含该许可证的副本。

signal()是标准的C,sigaction()不是。

如果你能够使用(也就是说你在POSIX系统上),那么使用sigaction(); 没有指定signal()是否重置了处理程序,意味着要移植,必须在处理程序中再次调用signal()。 更糟糕的是有一个种族:如果你快速连续得到两个信号,而第二个在你重新安装处理程序之前交付,你将会有默认的行动,这可能是要杀死你的过程。 另一方面, sigaction()保证使用“可靠的”信号语义。 您不需要重新安装处理程序,因为它永远不会被重置。 使用SA_RESTART,您也可以获得一些系统调用来自动重新启动(因此您不必手动检查EINTR)。 sigaction()有更多的select和可靠的,所以鼓励它的使用。

Psst …不要告诉我告诉过你的任何人,但是POSIX目前有一个函数bsd_signal(),它的作用就像signal(),但是却给出了BSD的语义,这意味着它是可靠的。 它的主要用途是移植假定可靠信号的旧应用程序,而POSIX不build议使用它。

我也build议在signal()上使用sigaction(),并想添加一个点。 sigaction()为您提供了更多选项,例如死亡进程的pid(可能使用siginfo_t结构)。