【发布时间】:2012-12-05 11:00:10
【问题描述】:
我在 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.)
【讨论】:
sig_atomic_t 标志在很大程度上就足够了,而且它是可移植的,即使对于非 Unix 系统也是如此。而当你需要做一些复杂的事情,又没有方便的地方轮询时,使用单独的线程确实是唯一的方法。对于中间情况...我从未听说过从信号写入管道,但这听起来是一个很好的折衷方案。
select 来执行它是没有问题的,那么管道听起来很不错解决方案。设置信号来解除线程阻塞也不是一件容易的事。
除了带有信号处理程序的传统 Unix 方式外,还有其他方式:
signalfd() 函数。您可以获得普通文件描述符并轮询它(使用select 或epoll)以获取传入信号。因此,当您处理信号时对它们没有任何限制——它只是普通的用户空间代码,因此您可以调用任何您想要的...EVFILT_SIGNAL 和 kqueue)【讨论】: