信号处理程序中的 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 <<
不可重入。
这意味着如果您在执行std::cout::operator <<
时引发了一个在其执行过程中也使用它的信号,则结果是未定义的。
所以,不。将其移至 route_signal
并不能解决此问题,您应该在其中替换 std::cout
的每个调用!
一种解决方法是设置一个标志表明该信号已被接收,并在它返回后在信号处理程序之外创建一个输出。
【讨论】:
这无论如何都不能回答我的问题,我没有问为什么它不安全【参考方案3】:如果我把打印移到 route_signal 里面会解决问题吗?
没有。
在 C++11 中有安全调用函数的列表吗?
出于实际目的,您可以做的唯一安全的事情是在信号处理程序中设置volatile sig_atomic_t
或无锁原子标志。 (N3690 intro.execution §1.9 ¶6)
我既不是 C 也不是 C++ 语言律师,但我相信 C++11 信号处理程序中允许符合 C 应用程序的任何内容。但是,该集合非常非常有限:abort
、quick_exit
、_Exit
和 signal
。 (ISO/IEC 9899:2011 §7.14.1.1 ¶5)。
如果唯一的解决方案是使用 write,你能给我看一个简短的例子吗,假设 route_signal 有 100 次打印,我应该用 write() 替换所有吗?这听起来很累,需要分配内存和释放...
更好的解决方案是重新设计您的程序以使用sigwait
或检查信号处理程序内是否安全设置了标志。
如果你坚持使用write
,并且如果你相信在你的 C++ 实现中调用信号处理程序是安全的——它可能是安全的,但同样,C++ 本身并不能保证——那么你只需一个编码问题。您需要自己弄清楚格式,记住即使在符合 POSIX 的系统上 malloc
和 free
也不是异步信号安全的。当然可以。
【讨论】:
以上是关于信号处理程序中的 C++ 打印?的主要内容,如果未能解决你的问题,请参考以下文章