让我解释一下:我已经在 Linux 上开发了一个应用程序,它分叉并执行一个外部二进制文件并等待它完成。结果由 fork + 进程独有的 shm 文件传达。整个代码封装在一个类中。
现在我正在考虑线程化进程以加快速度。有许多不同的类函数实例同时派生和执行二进制文件(使用不同的参数),并使用它们自己独特的 shm 文件来传达结果。
这个线程安全吗?如果我在一个线程中分叉,除了安全之外,还有什么需要注意的吗?非常感谢任何建议或帮助!
原文由 Ælex 发布,翻译遵循 CC BY-SA 4.0 许可协议
问题是 fork() 只复制调用线程,并且子线程中持有的任何互斥锁将永远锁定在分叉的子线程中。 pthread 解决方案是
pthread_atfork()
处理程序。这个想法是您可以注册 3 个处理程序:一个 prefork、一个父处理程序和一个子处理程序。当fork()
发生 prefork 在 fork 之前被调用并且预计会获得所有应用程序互斥体。父进程和子进程都必须分别释放父进程和子进程中的所有互斥锁。但这不是故事的结局!库调用
pthread_atfork
为库特定的互斥锁注册处理程序,例如 Libc 这样做。这是一件好事:应用程序不可能知道第三方库持有的互斥锁,因此每个库必须调用pthread_atfork
以确保在发生fork()
。问题是
pthread_atfork
处理程序调用无关库的顺序是未定义的(这取决于程序加载库的顺序)。所以这意味着从技术上讲,由于竞争条件,prefork 处理程序内部可能会发生死锁。例如,考虑这个序列:
fork()
有你的死锁,它与你自己的互斥锁或代码无关。
这实际上发生在我曾经参与的一个项目中。我当时找到的建议是选择 fork 或 threads,但不能同时选择两者。但是对于一些可能不实用的应用程序。