信号处理程序中的 C++ 打印?

Posted

技术标签:

【中文标题】信号处理程序中的 C++ 打印?【英文标题】:C++ printing in signal handlers? 【发布时间】:2021-04-27 11:31:12 【问题描述】:

我搜索了很多但没有人回答我的问题,我读到在这样的信号处理程序中使用 cout 是不安全的:

void ctrlZHandler(int sig_num) 
    //SIGTSTP-18
    std::cout << "smash: got ctrl-Z" << std::endl;
    SmallShell::route_signal(sig_num);

    如果我把打印移到 route_signal 里面会解决问题吗?

    在 C++11 中有安全调用函数的列表吗?

    如果唯一的解决方案是使用 write,你能给我看个简短的例子吗,假设 route_signal 有 100 个打印,我应该用write() 替换所有吗?这听起来很累,需要分配内存和释放......

【问题讨论】:

这是不安全的,因为写入 std::cout 时的缓冲区。但是你可以打开std::cout 来写没有缓冲蚂蚁那么它可能更安全。 signal safety 表示没有内存分配。并且没有缓冲 I/O,因为它不会阻塞信号(除非您已采取措施确保这些例程的信号被阻塞)。信号处理程序调用的所有例程都具有相同的约束。 请在您的问题中提供一些minimal reproducible example(一些带有main 的C++ 代码)。 至少,多介绍一下您的应用程序。它有一些事件循环吗?它是多线程的吗?您是否有权访问所有源代码?某些 C++ 代码是由软件(哪一个)生成的?请edit您的问题在其中添加几段。另请阅读Advanced Linux Programming 和syscalls(2)。花几个小时阅读 C++ 代码处理信号示例 是 ninja 构建器或 fish shell(很快将是 RefPerSys 项目)两者都是开源的,您可以下载和研究他们的源代码 另请阅读 signal(7) 和好的 operating system textbook 【参考方案1】:

信号处理程序需要快速运行并且是可重入的,这就是为什么它们不应该直接或间接调用像 cout

如果您是在受控条件下临时执行此操作以进行测试,则可能没问题,但请确保在处理程序完成之前不会再次触发您正在处理的信号,并注意流函数可能很慢,这可能会造成混乱也可以进行测试。

【讨论】:

这无论如何都不能回答我的问题,我没有问为什么它不安全 如果你知道它为什么不安全,你可以回答你自己的问题。 我问了我自己的建议 这回答了 1,并为您指明了 2 的正确方向(查找您正在开发的环境的可重入函数列表)。【参考方案2】:

不推荐在信号处理程序中使用std::cout 的原因是因为信号可能随时中断您正在运行的代码,而std::cout::operator &lt;&lt; 不可重入。

这意味着如果您在执行std::cout::operator &lt;&lt; 时引发了一个在其执行过程中也使用它的信号,则结果是未定义的。

所以,不。将其移至 route_signal 并不能解决此问题,您应该在其中替换 std::cout 的每个调用!

一种解决方法是设置一个标志表明该信号已被接收,并在它返回后在信号处理程序之外创建一个输出。

【讨论】:

这无论如何都不能回答我的问题,我没有问为什么它不安全【参考方案3】:
    如果我把打印移到 route_signal 里面会解决问题吗?

没有。

    在 C++11 中有安全调用函数的列表吗?

出于实际目的,您可以做的唯一安全的事情是在信号处理程序中设置volatile sig_atomic_t 或无锁原子标志。 (N3690 intro.execution §1.9 ¶6)

我既不是 C 也不是 C++ 语言律师,但我相信 C++11 信号处理程序中允许符合 C 应用程序的任何内容。但是,该集合非常非常有限:abortquick_exit_Exitsignal。 (ISO/IEC 9899:2011 §7.14.1.1 ¶5)。

    如果唯一的解决方案是使用 write,你能给我看一个简短的例子吗,假设 route_signal 有 100 次打印,我应该用 write() 替换所有吗?这听起来很累,需要分配内存和释放...

更好的解决方案是重新设计您的程序以使用sigwait 或检查信号处理程序内是否安全设置了标志。

如果你坚持使用write,并且如果你相信在你的 C++ 实现中调用信号处理程序是安全的——它可能是安全的,但同样,C++ 本身并不能保证——那么你只需一个编码问题。您需要自己弄清楚格式,记住即使在符合 POSIX 的系统上 mallocfree 也不是异步信号安全的。当然可以。

【讨论】:

以上是关于信号处理程序中的 C++ 打印?的主要内容,如果未能解决你的问题,请参考以下文章

C++ 中的高效消息工厂和处理程序

在 C++ 中捕获 windows 打印作业

用于库/应用程序组合的 C++ 中的错误处理/错误日志记录

处理 GUI 应用程序中的复杂规则(C++ 或 C#)

C++ 检测内存分配

深入理解C++中的异常处理机制