我们知道这printf
不是异步信号安全函数。以下是我的基本理解:
假设我们已经调用了printf
inmain
方法,因此内容被写入 stdio 缓冲区,就在缓冲区刷新到文件之前,信号到达并且信号处理程序也调用printf
,第二个printf
将其内容追加到缓冲区,现在是缓冲区第一次调用和第二次调用的内容不一致,这是不正确的,因此我们不能在信号处理程序中使用非异步安全函数。我的理解正确吗?
如果我的理解是正确的,那么异步安全函数如何解决这个问题呢?因为安全函数仍然需要处理缓冲区,其中仍然可能包含宝贵的调用的缓冲区数据?
答案1
printf
是非异步信号安全的,因为正如您所描述的,它最终会在没有同步的情况下操纵全局状态。为了增加乐趣,它不一定是可重入的。在您的示例中,信号可能会在第一个printf
运行时处理,而第二个信号printf
可能会扰乱第一个调用的状态。
推荐的异步信号安全方法是让信号处理程序在某处设置一个标志,并让主程序流处理该标志。这可以避免重新进入、序列化输出的问题,并有助于保持信号处理程序的速度。
答案2
我的理解正确吗?
大多。还有一个问题是,在调整缓冲区的偏移量和大小时,嵌套的 printf 调用会互相踩踏,这不仅会导致数据不一致,还会导致崩溃。
异步安全函数如何解决这个问题?
有两种异步信号安全函数:
像 strlen(3) 这样的可重入函数,除了用于保存局部变量、参数和返回值的内存之外,不会修改任何内存。
函数是简单的系统调用包装器,如kill(2)、waitpid(2)等:它们的用户态部分是完全可重入的,如上所述,而对于内核部分,内核会处理一切。