我正要为我们这里的应用程序添加一个额外的信号处理程序,我注意到作者已经习惯sigaction()
了设置其他信号处理程序.我打算用signal()
.按照惯例我应该使用,sigaction()
但如果我是从头开始写,我应该选择哪个?
使用sigaction()
除非你有非常令人信服的理由不这样做.
所述signal()
接口具有对其有利古代(并且因此可用性),它是在C标准中定义.然而,它有许多不受欢迎的特性sigaction()
可以避免 - 除非你使用明确添加的标志sigaction()
来允许它忠实地模拟旧的signal()
行为.
signal()
当前处理程序执行时,该函数不一定(必然)阻止其他信号到达; sigaction()
可以阻止其他信号,直到当前处理程序返回.
该signal()
功能(通常)将信号动作重置为SIG_DFL
(默认)几乎所有信号.这意味着signal()
处理程序必须重新安装自己作为其第一个操作.它还会在检测到信号和重新安装处理程序之间打开一个漏洞窗口,在此期间,如果信号的第二个实例到达,则会发生默认行为(通常是终止,有时带有偏见 - 也称为核心转储).
signal()
系统之间的确切行为有所不同 - 标准允许这些变化.
这些通常是使用sigaction()
而不是使用的好理由signal()
.然而,界面sigaction()
无疑更加繁琐.
你使用这两种中的哪,不要被诸如替代信号接口被诱惑
sighold()
,
sigignore()
,
sigpause()
和
sigrelse()
.它们名义上是替代品sigaction()
,但它们只是几乎没有标准化,并且存在于POSIX中以便向后兼容而不是严格使用.请注意,POSIX标准表明它们在多线程程序中的行为是未定义的.
多线程程序和信号是另一个复杂的故事. 据我所知,无论是signal()
和sigaction()
在多线程应用程序确定.
Cornstalks 观察到:
Linux手册页
signal()
说:
的效果
signal()
在多线程程序未指定.因此,我认为
sigaction()
是唯一可以在多线程进程中安全使用的方法.
那很有意思.在这种情况下,Linux手册页比POSIX更具限制性.POSIX指定signal()
:
如果进程是多线程的,或者进程是单线程的,并且执行信号处理程序而不是以下结果:
的过程调用
abort()
,raise()
,kill()
,pthread_kill()
,或sigqueue()
,以产生没有被阻塞的信号待解锁的信号在解锁之前被解除并在其解锁之前被传递
如果信号处理程序引用除
errno
静态存储持续时间之外的任何对象,而不是通过为声明为的对象赋值volatile sig_atomic_t
,或者如果信号处理程序调用此标准中定义的任何函数而不是其中一个函数,则行为是未定义的.信号概念.
所以POSIX清楚地指定signal()
了多线程应用程序的行为.
然而,sigaction()
在基本上所有情况下都是首选 - 并且应该使用可移植的多线程代码,sigaction()
除非有一个压倒性的原因导致它不能(例如"仅使用标准C定义的函数" - 是的,C11代码可以是多个-threaded).基本上这个答案的开头部分也是如此.
对我来说,以下这一行足以决定:
sigaction()函数为控制信号提供了更全面,更可靠的机制。新的应用程序应该使用sigaction()而不是signal()
http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html#tag_03_690_07
无论您是从头开始还是修改旧程序,sigaction都是正确的选择。
它们是OS信号设备的不同接口.人们应该更喜欢使用sigaction来发出信号,因为signal()具有实现定义(通常易于竞争)的行为,并且在Windows,OS X,Linux和其他UNIX系统上表现不同.
请参阅此安全说明以获取详细信
signal()是标准C,sigaction()不是。
如果您可以使用任何一个(即您在POSIX系统上),请使用sigaction();。尚不确定signal()是否重置处理程序,这意味着要变得可移植,您必须在处理程序内部再次调用signal()。更糟糕的是,这是一场竞赛:如果您连续快速地收到两个信号,并且在重新安装处理程序之前传递了第二个信号,则您将拥有默认操作,这可能会杀死您的进程。 另一方面,保证sigaction()使用“可靠”的信号语义。您无需重新安装该处理程序,因为它将永远不会重置。使用SA_RESTART,您还可以获得一些系统调用以自动重新启动(因此您不必手动检查EINTR)。 sigaction() 具有更多选择并且可靠,因此鼓励使用它。
Psst ...告诉我的任何人都没有,但是POSIX当前具有bsd_signal()函数,其功能类似于signal()但具有BSD语义,这意味着它是可靠的。它的主要用途是移植假定可靠信号的旧应用程序,而POSIX不建议使用它。