我正在使用Unix上的C++。信号处理程序和本地状态
说我有一个长时间运行的函数来执行某些操作,例如从文件中读取数据并解析它。在这个函数中,我将从文件中读取的东西保存在局部变量num_read
中。
我想在自定义信号处理程序中捕获CTRL + c并打印num_read
的值。
我能想到的唯一方法是在堆上分配num_read
并将其地址存储在可由我的信号处理程序访问的全局变量中。有没有更优雅的方式?
我正在使用Unix上的C++。信号处理程序和本地状态
说我有一个长时间运行的函数来执行某些操作,例如从文件中读取数据并解析它。在这个函数中,我将从文件中读取的东西保存在局部变量num_read
中。
我想在自定义信号处理程序中捕获CTRL + c并打印num_read
的值。
我能想到的唯一方法是在堆上分配num_read
并将其地址存储在可由我的信号处理程序访问的全局变量中。有没有更优雅的方式?
答案是否定的。有没有 之间的信号处理程序和除全局 变量之外的其余代码之间进行通信的方式。
此外,您只能在 信号处理程序中执行非常非常有限数量的操作。例如,您不能在std::ostream
, 上使用<<
,也不能使用printf
。在Unix下处理信号的 的通常方式是在单独的 线程中捕获它们。替代方案(也适用于其他操作系统)为 ,用于定义全局变量sig_atomic_t
,该变量设置在 信号处理程序中,并在主循环中轮询。 (在你的情况, 例如,你可能每次更新 num_read
时间轮询吧)
或者,对于讨厌线程(我!)的unix人来说,更传统的处理信号的方式是使用自我管道......更好!保证以及select()循环被唤醒(有一堆竞争条件与唤醒wait()循环的全局标志方法,需要一些sigsuspend/sigprocmask杂技)。我总是推荐一种自我管道,以提高其便携性,坚固性和完全避免所有细微问题。 –
@NicholasWilson我同意线程经常被滥用,但他们确实有用。对于OP所要做的事情,sig_atomic_t标志在很大程度上是足够的,它甚至可以移植到非Unix系统。而当你需要做一些复杂的事情,并且没有方便的地方进行投票时,使用单独的线程才是真正的唯一途径。对于中间情况......我从来没有听说过从信号写入管道,但这听起来像是一个很好的妥协。 –
unix解决信号问题的“传统”解决方案早在线程来到unix之前,更不用说pthread了!自我管理技巧是一个绝对的经典,既非常简单,也避免了所有的竞争条件。我当然不能写一个基于标志的解决方案的实现,而不检查手册并做一些大脑弯曲;如果信号在检查后立即触发,那么主循环不会被唤醒,并且不会很快检查标志?另一方面,我可以在头顶上写一个自我管道解决方案,它确实没有比赛和强劲。 –
除了传统的Unix方式与信号处理,还有其它:
signalfd()
函数存在。您可以获取常用文件描述符并对其进行轮询(使用select
或epoll
)以获取传入信号。所以,当你处理一个信号没有适当的给他们任何限制 - 它只是平常用户空间代码,这样你就可以调用任何你想要的...EVFILT_SIGNAL
和kqueue
)
你有什么Unix? – zaufi
OS X和Debian。 – adrianN