sigaction和signal有什么区别?
我正要为我们在这里的应用程序添加一个额外的信号处理程序,并且我注意到作者使用了sigaction来设置其他信号处理程序。 我打算使用信号。 遵循约定,我应该使用sigaction,但是如果我是从头开始写的,应该select哪一个?
使用sigaction()
除非你有非常令人信服的理由不这样做。
signal()
接口具有古代性(因此可用),并且在C标准中定义。 尽pipe如此, sigaction()
避免了一些不受欢迎的特性 – 除非使用显式添加到sigaction()
的标志来忠实地模拟旧的signal()
行为。
- 在当前处理程序执行时,
signal()
函数不会(必然)阻止其他信号到达;sigaction()
可以阻止其他信号,直到当前处理程序返回。 -
signal()
函数(通常)会将信号操作重置为几乎所有信号的SIG_DFL
(默认值)。 这意味着signal()
处理程序必须重新安装自己作为其第一个操作。 它还会在信号被检测到和处理程序重新安装期间打开一个漏洞窗口,在此期间,如果信号的第二个实例到达,默认行为(通常会终止,有时会带有偏见 – 又名核心转储)。 -
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结构)。
- 我怎样才能捕获SIGSEGV(分段错误),并得到在Android上的JNI下的堆栈跟踪?
- 在Perl 5中,如何获得发送信号的进程的PID?
- 如何防止与django post_save信号码冲突?
- SIGSTOP和SIGTSTP有什么区别?
- POSIX线程和信号
- 通过使用BookSleeve的ConnectionUtils.Connect(),使用SignalR和Redis messagebus进行故障转移
- 在不locking互斥锁的情况下调用pthread_cond_signal
- 核心转储在Mac OS X中编写的?
- SignalR 2.0错误:无法加载文件或程序集Microsoft.Owin.Security