c++ - 从线程内 fork 是否安全?

标签 c++ linux multithreading process fork

让我解释一下:我已经在 Linux 上开发了一个应用程序,它 fork 并执行一个外部二进制文件并等待它完成。结果由 fork + 进程独有的 shm 文件传达。整个代码封装在一个类中。

现在我正在考虑对流程进行线程化以加快速度。有许多不同的类函数实例同时派生和执行二进制文件(使用不同的参数),并使用它们自己独特的 shm 文件来传达结果。

这个线程安全吗?如果我在一个线程中 fork ,除了安全之外,还有什么需要注意的吗?非常感谢任何建议或帮助!

最佳答案

问题是 fork() 只复制调用线程,并且子线程中持有的任何互斥锁将永远锁定在 fork 的子线程中。 pthread 解决方案是 pthread_atfork() 处理程序。这个想法是您可以注册 3 个处理程序:一个 prefork、一个父处理程序和一个子处理程序。当 fork() 发生时 prefork 在 fork 之前被调用,并且预期会获得所有应用程序互斥体。父进程和子进程都必须分别释放父进程和子进程中的所有互斥锁。

这不是故事的结局!库调用 pthread_atfork 来为库特定的互斥锁注册处理程序,例如 Libc 就是这样做的。这是一件好事:应用程序不可能知道第三方库持有的互斥锁,因此每个库都必须调用 pthread_atfork 以确保在发生 fork()

问题在于不相关的库调用 pthread_atfork 处理程序的顺序是未定义的(这取决于程序加载库的顺序)。所以这意味着从技术上讲,由于竞争条件,prefork 处理程序内部可能会发生死锁。

例如,考虑这个序列:

  1. 线程 T1 调用 fork()
  2. 在 T1 中调用 libc prefork 处理程序(例如,T1 现在拥有所有 libc 锁)
  3. 接下来,在线程 T2 中,第 3 方库 A 获取其自己的互斥体 AM,然后进行需要互斥体的 libc 调用。这会阻塞,因为 libc 互斥锁由 T1 持有。
  4. 线程 T1 为库 A 运行 prefork 处理程序,该处理程序阻塞等待获取由 T2 持有的 AM。

您的死锁与您自己的互斥锁或代码无关。

这实际上发生在我曾经参与的一个项目中。我当时找到的建议是选择 fork 或 threads,但不能同时选择两者。但是对于一些可能不实用的应用程序。

关于c++ - 从线程内 fork 是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6078712/

相关文章:

c++ - 如何使用 Github Actions 中的 MSVC 编译器?

c++ - 如何获取QSqlTableModel中的值?

linux - bash 如何使用 CTRL+C 杀死子进程

java - 单线程与多线程 : Mergesort performance comparison

c++ - 了解使用 std::condition_variable 的示例

c++ - 如何防止在构造函数或析构函数中调用虚函数?

c++ - QT中如何通过套接字传输较大的对象?

linux - 使用linux从文本文件中提取数据

java - JUnit 中的 "Could not find class"

c - 下面的代码有什么问题?预期 X 由线程 Func 1 修改,随后 X 由线程 Func 2 修改