在父创建线程后调用fork()的正确方法?

时间:2017-03-08 18:01:38

标签: multithreading fork posix

我正在实现一个带有第三方插件的复杂应用程序,我想在子进程中运行插件代码以实现隔离。父进程需要多线程,但我已经读过fork may be unsafe in multithreaded processes,特别是如果你没有立即调用execve,那就是pthread_atfork is not a complete solution

其他复杂的应用程序对此做了什么?我知道Chrome同时使用子进程和多线程,因此它必须可能

2 个答案:

答案 0 :(得分:3)

多线程程序中fork()的行为是明确定义的。成功时,子进程只有一个线程 - 在父程序中调用fork()的线程。虽然 可能是一个问题,但实际上是否问题取决于具体情况。

多线程程序出现{{1}问题的时间是什么时候?

fork()在多线程程序中出现问题的主要原因是子进程依赖于互斥锁,条件变量等,其他线程无法再依赖它们进行操作。例如,如果子进程需要获取它尚未保存的进程专用互斥锁,那么可能是该分支在该分支时由另一个线程持有该互斥锁。在这种情况下,它永远不会在子进程中释放,因为在子进程中不存在可以释放它的线程。

何时fork() 多线程程序出现问题?

涉及fork()的一个常见习语是通过执行另一个程序来立即跟进。无论父母的线程如何,这都没问题。

或者,如果子进程不依赖于任何有问题的资源,则不需要做任何特殊操作。请注意,进程共享 interthread对象在这个意义上并不“有问题”。这种情况相当普遍,听起来可能就是你的情况。

否则,如果父母的分叉线程可以并且确实获得了孩子在分叉之前需要的所有进程私有的线程间资源,那么这不是问题。 fork()注册的处理程序在某些情况下可以帮助解决这个问题,但在其他情况下,在fork调用的直接环境中进行处理更有意义。

<强> 总体

您提出的问题好像pthread_atfork()对于多线程程序来说是一个深刻且麻烦的问题。这当然是一个应该考虑的问题,通常最好避免同时使用多个线程和多个进程。因此,因为您需要多个进程以便具有单独的地址空间以及可能加载插件的名称空间,您可能应该考虑在现在使用线程的任何地方使用单独的进程。另一方面,如果你运用一些思考和关心,你可以使它适用于你的多线程进程来分叉子项并与它们交互。

答案 1 :(得分:2)

如果您无法确保fork仅在安全的情况下使用,如John Bollinger's answer中所述,一般的解决方法是使用&#34; fork服务器&#34;。在创建任何线程之前,原始进程分叉一次。子进程是fork服务器;它仍然是单线程的。父进程现在继续并创建其线程。只要父母想要调用fork,它就会向fork服务器发送一条消息,要求它这样做。

如果(终极)子进程也需要与父进程通信,最简单的方法是让父进程为每个子进程的stdin和stdout创建管道,然后转移那些子进程的子进程。使用SCM_RIGHTS special message管道到fork服务器。您可以同时发送文件描述符和数据。 fork服务器和父服务器之间的通信协议可能需要非常花哨 - 请查看posix_spawn API,以获得您可能想要的所有旋钮的完整列表。 (注意:posix_spawn只是fork周围的库包装;使用它会避免原始问题。)

fork服务器还负责调用waitpid并将退出状态转发回父级。这比它应该更复杂,因为等待下一个可能事件(selectpoll)的标准API不接受进程ID作为等待的事情之一。 (BSD&#39; s kqueue 确实,但你可能不在BSD上。)你必须与SIGCHLD和管道进行混乱的舞蹈 - 而不是自我。