当前位置:  开发笔记 > 编程语言 > 正文

为什么只能安全地从信号处理程序中调用异步信号安全功能?

如何解决《为什么只能安全地从信号处理程序中调用异步信号安全功能?》经验,为你挑选了1个好方法。

我仍然有点困惑,为什么接收信号并从该信号处理程序中调用非异步安全函数是不安全的.有人可以解释这背后的原因,并可能尝试给我一些参考资料,我可以跟着自己阅读更多内容吗?

换句话说,我问为什么在信号处理程序中调用printf是不安全的.是因为内部进程问题和可能的竞争条件导致两个可能的printf没有保护调用,或者是因为进程争用到同一个资源(在本例中为stdout).假设进程A中的线程正在调用printf而另一个线程接收该信号然后调用printf.可能是因为这里的内核不知道该怎么做,因为它无法区分这两个调用.



1> Sam Varshavc..:

假设进程A中的线程正在调用printf而另一个线程接收该信号然后调用printf.可能是因为这里的内核不知道该怎么做,因为它无法区分这两个调用.

这不是内核会有问题.这是你的应用程序本身.printf不是内核函数.它是您的应用程序使用的C库中的一个函数.printf实际上是一个相当复杂的功能.它支持各种输出格式.

此格式化的最终结果是格式化的输出字符串,该字符串写入标准输出.这个过程本身也涉及一些工作.格式化的输出字符串将写入内部stdout文件句柄的输出缓冲区.每当发生某些定义的条件时,即当输出缓冲区已满时,和/或每当换行符被写入时,输出缓冲区都会被刷新(并且此时内核只接管并将定义的数据块写入文件).输出流.

所有这些都由输出缓冲区的内部数据结构支持,您不必担心它,因为它是C库的工作.现在,信号可以在任何时候到达,同时printf它可以工作.我的意思是,在任何时候.它可能会printf在更新输出缓冲区的内部数据结构时到达,并且它们处于临时不一致状态,因为printf尚未完成更新.

示例:在现代C/C++实现中,printf可能不是信号安全的,但它是线程安全的.多个线程可用于printf写入标准输出.线程有责任在它们之间协调这个过程,以确保最终输出实际上是有意义的,并且它不会随机地从多个线程的输出混乱,但这不是重点.

重点是printf线程安全,这通常意味着某个地方有一个涉及该过程的互斥体.因此,可能发生的事件序列是:

printf 获取内部互斥锁.

printf继续其工作格式化字符串并将其写入stdout输出缓冲区.

printf完成之前,可以释放获取的互斥锁,信号到达.

现在,内部mutex被锁定了.关于信号处理程序的事情是,它通常没有指定在一个进程中哪个线程处理信号.给定的实现可能会随机选择一个线程,或者它可能总是选择当前正在运行的线程.在任何情况下,它都可以选择锁定的线程printf,这里是为了处理信号.

所以现在,你的信号处理程序运行,它也决定调用printf.因为printf内部互斥锁被锁定,所以线程必须等待互斥锁解锁.

等一下

等一下

因为,如果您正在跟踪事物:互斥锁被中断的线程锁定以服务信号.在线程恢复运行之前,互斥锁不会被解锁.但是直到信号处理程序终止并且线程恢复运行才会发生这种情况,但信号处理程序现在正在等待互斥锁解锁.

你是骨头.

当然,现在printf可能会使用等效的C++ std::recursive_mutex来避免这个问题,但即使这样也无法解决信号引入的所有可能的死锁.

总而言之,根据定义,它"从信号处理程序中接收信号并调用非异步安全功能不安全"的原因是因为它不是.从信号处理程序中调用非异步安全函数是不安全的"因为信号是异步事件,并且由于它不是异步安全函数,所以根据定义你不能.水是湿的,因为它是水,并且无法从异步信号处理程序调用异步不安全的函数.

推荐阅读
mobiledu2402852357
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有