gpt4 book ai didi

c - 对于线程程序中的信号处理程序,fork(应该)是安全的吗?

转载 作者:太空狗 更新时间:2023-10-29 16:27:07 27 4
gpt4 key购买 nike

我真的不确定 POSIX 在存在线程和信号的情况下对 fork 的安全性提出的要求。 fork 被列为异步信号安全函数之一,但是如果库代码有可能注册了非异步信号安全的 pthread_atfork 处理程序,这是否否定了 fork 的安全性?答案是否取决于运行信号处理程序的线程是否正在使用 atfork 处理程序所需的资源?或者换一种说法,如果 atfork 处理程序使用同步资源(互斥体等),但是 fork 是从信号处理程序调用的,该信号处理程序在从不访问这些资源的线程中执行,是程序符合?

基于这个问题,如果使用 pthread_atfork 建议的习惯用法在系统库内部实现“线程安全” fork (获取预 fork 处理程序中的所有锁并释放所有锁parent and child postfork handlers),那么 fork 在线程程序中从信号处理程序中使用是否安全?处理信号的线程是否可能正在调用 mallocfopen/fclose 并持有一个全局变量?锁,导致 fork 期间出现死锁?

最后,即使 fork 在信号处理程序中是安全的,在信号处理程序中 fork 然后从信号处理程序返回还是调用信号处理程序中的 fork 总是需要在信号处理程序返回之前对 _exitexec 函数家族之一进行后续调用?

最佳答案

尽我所能回答所有子问题;我很抱歉其中一些内容比理想情况下更模糊:

If there is a possibility that library code has registered pthread_atfork handlers which are not async-signal-safe, does this negate the safety of fork?

是的。 fork documentation明确提到这一点:

   When the application calls fork() from a signal handler and any of the
fork handlers registered by pthread_atfork() calls a function that is
not asynch-signal-safe, the behavior is undefined.

当然,这意味着您实际上不能将 pthread_atfork() 用于其预期目的,即使多线程库对认为它们是单线程的进程透明,因为没有 pthread同步函数是异步信号安全的;这在规范中被称为缺陷,请参阅 http://www.opengroup.org/austin/aardvark/latest/xshbug3.txt (搜索“L16723”)。

Does the answer depend on whether the thread in which the signal handler is running could be in the middle of using a resource that the atfork handlers need? Or said a different way, if the atfork handlers make use of synchronization resources (mutexes, etc.) but fork is being called from a signal handler which executed in a thread that never accesses these resources, is the program conforming?

严格来说答案是否定的,因为根据规范,函数要么是异步信号安全的,要么不是;没有“在某些情况下安全”的概念。在实践中,您可能会侥幸逃脱,但您很容易受到笨拙但正确的实现的影响,该实现没有按照您期望的方式对其资源进行分区。

Building on this question, if "thread-safe" forking is implemented internally in the system library using the idioms suggested by pthread_atfork (obtain all locks in the prefork handler and release all locks in both the parent and child postfork handlers), then is fork ever safe to use from signal handlers in a threaded program? Isn't it possible that the thread handling the signal could be in the middle of a call to malloc or fopen/fclose and holding a global lock, resulting in deadlock during fork?

如果以这种方式实现,那么你是对的,来自信号处理程序的 fork() 永远不会安全,因为如果调用线程已经持有,则尝试获取锁可能会死锁它。但这意味着使用这种方法的实现不符合要求。

以 glibc 为例,它并没有这样做 - 相反,它采用两种方法:首先,它获得的锁是递归的(所以如果当前线程已经拥有它们,它们的锁计数将简单地是增加);此外,在子进程中,它只是单方面覆盖所有锁 - 请参阅 nptl/sysdeps/unix/sysv/linux/fork.c 的摘录:

  /* Reset the file list.  These are recursive mutexes.  */
fresetlockfiles ();

/* Reset locks in the I/O code. */
_IO_list_resetlock ();

/* Reset the lock the dynamic loader uses to protect its data. */
__rtld_lock_initialize (GL(dl_load_lock));

其中每个 resetlocklock_initialize 函数最终都会调用 glibc 的内部等效 pthread_mutex_init(),有效地重置互斥锁,而不管任何等待程序.

我认为理论是,通过获得(递归)锁,可以保证没有其他线程会接触数据结构(至少以可能导致崩溃的方式),然后重置各个锁确保资源不会被永久阻止。 (重置当前线程的锁是安全的,因为现在没有其他线程争用数据结构,而且在使用锁的任何函数返回之前确实不会)。

我不是 100% 相信这涵盖了所有可能发生的情况(尤其是因为如果/当信号处理程序返回时,刚刚被盗锁的函数将尝试解锁它,而内部递归解锁函数不会防止解锁太多次!) - 但似乎可以在异步信号安全递归锁之上构建一个可行的方案

Finally, even if fork is safe in signal handlers, is it safe to fork in a signal handler and then return from the signal handler, or does a call to fork in a signal handler always necessitate a subsequent call to _exit or one of the exec family of functions before the signal handler returns?

我假设您是在谈论子进程? (如果 fork() 是异步信号安全的意味着什么,那么应该可以在父级中返回!)

没有在规范中找到任何其他说明(尽管我可能错过了)我相信它应该安全 - 至少,从信号处理程序返回的意义上“安全”在子进程中并不意味着未定义的行为本身,尽管多线程进程刚刚 fork 的事实可能意味着 exec*()_exit() 可能是最安全的做法。

关于c - 对于线程程序中的信号处理程序,fork(应该)是安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4453822/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com