更新时间:2021-10-17 21:52:57
问题在于 fork() 只复制调用线程,子线程中持有的任何互斥锁将永远锁定在分叉子线程中.pthread 解决方案是 pthread_atfork()
处理程序.这个想法是你可以注册 3 个处理程序:一个 prefork、一个父处理程序和一个子处理程序.当 fork()
发生时,在 fork 之前调用 prefork 并期望获得所有应用程序互斥锁.父进程和子进程都必须分别释放父进程和子进程中的所有互斥锁.
The problem is that fork() only copies the calling thread, and any mutexes held in child threads will be forever locked in the forked child. The pthread solution was the pthread_atfork()
handlers. The idea was you can register 3 handlers: one prefork, one parent handler, and one child handler. When fork()
happens prefork is called prior to fork and is expected to obtain all application mutexes. Both parent and child must release all mutexes in parent and child processes respectively.
这还不是故事的结局!库调用 pthread_atfork
来为库特定的互斥体注册处理程序,例如 Libc 就是这样做的.这是一件好事:应用程序不可能知道第 3 方库持有的互斥锁,因此每个库都必须调用 pthread_atfork
以确保在发生 时清除它自己的互斥锁>fork()
.
This isn't the end of the story though! Libraries call pthread_atfork
to register handlers for library specific mutexes, for example Libc does this. This is a good thing: the application can't possibly know about the mutexes held by 3rd party libraries, so each library must call pthread_atfork
to ensure it's own mutexes are cleaned up in the event of a fork()
.
问题在于,pthread_atfork
处理程序为不相关的库调用的顺序是未定义的(这取决于程序加载库的顺序).因此,这意味着从技术上讲,由于竞争条件,可能会在 prefork 处理程序内部发生死锁.
The problem is that the order that pthread_atfork
handlers are called for unrelated libraries is undefined (it depends on the order that the libraries are loaded by the program). So this means that technically a deadlock can happen inside of a prefork handler because of a race condition.
例如,考虑这个序列:
fork()
这是您的死锁,它与您自己的互斥锁或代码无关.
There's your deadlock and its unrelated to your own mutexes or code.
这实际上发生在我曾经参与过的一个项目中.我当时找到的建议是选择 fork 或 thread,但不能两者兼而有之.但对于一些可能不实用的应用程序.
This actually happened on a project I once worked on. The advice I had found at that time was to choose fork or threads but not both. But for some applications that's probably not practical.