【问题标题】:Signal handler and local state信号处理程序和本地状态
【发布时间】:2012-12-05 11:00:10
【问题描述】:

我在 Unix 上使用 C++。

假设我有一个长时间运行的函数,它可以做一些事情,例如从文件中读取内容并解析它。在这个函数中,我在本地变量num_read 中记录我从文件中读取的内容。

我想在自定义信号处理程序中捕获 CTRL+c 并打印 num_read 的值。

我能想到的唯一方法是在堆上分配num_read 并将其地址存储在我的信号处理程序可以访问的全局变量中。有没有更优雅的方式?

【问题讨论】:

    标签: c++ unix signals


    【解决方案1】:

    答案是否定的。之间没有没有的交流方式 信号处理程序和除全局之外的其余代码 变量。

    另外,你只能做非常非常有限的事情 信号处理程序。您不能在 std::ostream 上使用 <<, 例如,你也不能打电话给printf。通常的方式 在 Unix 下处理信号是将它们捕获在一个单独的 线。替代方案(也适用于其他操作系统)是 定义一个全局变量sig_atomic_t,设置在 信号处理程序,并在主循环中轮询。 (在你的情况下, 例如,您可能会在每次更新时轮询它 num_read.)

    【讨论】:

    • 或者,对于讨厌线程的 unix 人(我!),更传统的处理信号的方法是使用 self-pipe... 更好!还保证 select() 循环被唤醒(使用全局标志方法唤醒 wait() 循环时存在大量竞争条件,需要一些 sigsuspend/sigprocmask 杂技)。我总是推荐自管,因为它的便携性、健壮性和完全避免所有微妙的问题。
    • @NicholasWilson 我同意线程经常被滥用,但它们确实有用。对于 OP 正在尝试做的事情,sig_atomic_t 标志在很大程度上就足够了,而且它可移植的,即使对于非 Unix 系统也是如此。而当你需要做一些复杂的事情,又没有方便的地方轮询时,使用单独的线程确实是唯一的方法。对于中间情况...我从未听说过从信号写入管道,但这听起来是一个很好的折衷方案。
    • “传统的”unix 信号问题解决方案早在线程出现在 unix 之前就已经存在,更不用说 pthreads了!自管技巧绝对是经典,既非常简单又避免了所有竞争条件。如果不检查手册并做一些脑筋急转弯,我当然无法编写基于标志的解决方案的实现;如果信号在检查之后触发,所以主循环没有被唤醒并且不会很快检查标志怎么办?另一方面,我可以不由自主地编写一个自管解决方案,它确实是无竞争且健壮的。
    • @NicholasWilson 如果非信号代码可以进入无限等待,那么我同意标志解决方案不可行;在线程前的日子里,我一直看到的解决方案是在 select 上设置一个超时(这样等待就不会被绑定)。但正如我所说,当处理对于信号处理程序来说过于复杂时,并且等待主线程执行select 来执行它是没有问题的,那么管道听起来很不错解决方案。设置信号来解除线程阻塞也不是一件容易的事。
    【解决方案2】:

    除了带有信号处理程序的传统 Unix 方式外,还有其他方式:

    • 从 Linux 内核 2.6.22 开始,存在 signalfd() 函数。您可以获得普通文件描述符并轮询它(使用selectepoll)以获取传入信号。因此,当您处理信号时对它们没有任何限制——它只是普通的用户空间代码,因此您可以调用任何您想要的...
    • 据我所知,对于 OS X,kqueue 中存在类似的功能(在此站点或互联网上搜索 EVFILT_SIGNALkqueue

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-06
      • 2023-03-20
      • 1970-01-01
      • 2012-01-24
      • 2011-11-18
      相关资源
      最近更新 更多