我只是想知道我是否可以在信号处理程序中调用非异步安全函数 来自Linux手册页信号的引言(7):
如果信号中断了不安全函数的执行,并且处理程序调用了不安全函数,则程序的行为未定义。
和TLPI:
SUSv3指出,表21-1中未列出的所有函数(异步安全函数列表)都被认为对信号不安全,但指出只有在调用信号处理程序中断执行不安全的功能,处理程序本身也调用不安全的函数。
我对上述引文的解释是 只有在信号处理程序没有中断非异步安全函数时才能从信号处理程序中调用非异步安全函数是安全的
例如,我为SIGINT安装了一个处理程序,它调用一个不安全的函数,假设是crypt(3)
,它是不可重入的,即不安全。
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = handler;
sigaction(SIGINT, &sa, NULL);
我还在printf()
中的无限循环中调用main()
,并且我只运行主线程。
问题出在这个简单的例子中,当处理程序中断printf()
的执行并且它调用不安全的函数时,我看不到任何不好的事情。 AFAK,{{ 1}}将获取一个控制台锁并具有一个内部缓冲区来执行缓冲I / O,但在此示例中其状态为一致。虽然printf()
返回静态分配的字符串,但它不与其他函数或线程共享。
我误解了什么吗?我希望有人向我澄清一下,始终不安全让信号处理程序中断主程序中不安全功能的执行,并且本身也会调用不安全的功能,或者在某些情况下这样做是安全的(例如上面的简单例子)?
答案 0 :(得分:3)
如果信号在主程序中中断任何 async-unsafe函数,则在信号处理程序中调用任何 async-unsafe函数是不安全的。异步不安全的函数不需要彼此有任何关系 - 结果是未定义的。
因此,在信号处理程序中安全地调用异步不安全函数的唯一方法是确保在调用aysnc-unsafe函数时永远不会发生信号。一种方法是使用相应的sigblock / sigsetmask调用将每次调用包装到任何异步不安全函数,以确保在不安全函数运行时不会传递信号。另一种方法是让主程序在调用async-unsafe函数时设置/清除sigatomic
标志,并让信号处理程序在尝试调用async-unsafe函数之前检查该标志。
使用同步信号(例如SIGFPE
和SIGSEGV
之类的东西)会更好一些,因为在那里你可以确保异步不安全的函数永远不会触发这些信号并且您不允许(或关心)与kill
异步发送这些信号。这需要一些小心 - 如果你有SIGSEGV
的信号处理程序捕获写保护内存的写入,你需要确保你永远不会以一种方式将写保护的内存传递给async-unsafe函数它可能会触发你的处理程序。