【问题标题】:Calling fork on a multithreaded process在多线程进程上调用 fork
【发布时间】:2019-05-05 04:28:48
【问题描述】:

我对在多线程进程上使用 fork 有疑问。 如果一个进程有多个线程(已经使用 pthread_create 创建并执行了 pthread_join)并且我调用了 fork,它会复制分配给子进程中线程的相同函数还是创建一个我们可以重新分配函数的空间?

【问题讨论】:

  • 别这样,好吗?我曾经在一个产品上工作,其中一个多线程进程需要偶尔启动其他进程。我们的策略是让它在启动时创建一个单线程辅助进程,然后再创建任何新线程。然后,每当它需要启动一个新的子进程时,它就会向助手发送一条消息,要求助手执行此操作。
  • 好的,既然你创建了一个单线程进程并启动了新进程,那么子进程总是有一个线程(执行的主线程)?
  • 要明确一点,长寿的主进程首先创建了辅助进程,然后创建了很多线程。创建助手后,它从未直接创建任何其他进程。辅助进程没有创建任何新线程。它是严格的单线程的,这使得助手可以安全地创建新进程。由助手创建的瞬态子进程没有任何限制。他们可以做任何他们需要做的事情。

标签: multithreading operating-system system-calls


【解决方案1】:

仔细阅读 POSIX 关于fork() 和线程的说明。特别是:

  • 应使用单个线程创建进程。如果多线程进程调用fork(),则新进程应包含调用线程及其整个地址空间的副本,可能包括互斥锁和其他资源的状态。因此,为避免错误,子进程只能执行异步信号安全操作,直到调用其中一个 exec 函数。

子进程将在调用线程的上下文中运行一个线程。原始进程的其他部分可能被不再存在的线程占用(例如,互斥锁可能被锁定)。

基本原理部分(链接页面下方)说:

POSIX 程序员调用fork() 有两个原因。一个原因是在同一个程序中创建一个新的控制线程(这最初只能在 POSIX 中通过创建一个新进程来实现);另一种是创建一个运行不同程序的新进程。在后一种情况下,对fork() 的调用很快就会调用exec 函数之一。

使fork() 在多线程世界中工作的一般问题是如何处理所有线程。有两种选择。一种是将所有线程复制到新进程中。这会导致程序员或实现处理在系统调用上挂起的线程或可能即将执行不应在新进程中执行的系统调用的线程。另一种选择是只复制调用fork() 的线程。这造成了进程本地资源的状态通常保存在进程内存中的困难。如果没有调用fork() 的线程持有资源,则该资源永远不会在子进程中释放,因为其任务是释放资源的线程在子进程中不存在。

当程序员编写多线程程序时,pthread_create() 函数提供了fork() 的首次使用,即在同一程序中创建新线程。因此,fork() 函数仅用于运行新程序,在调用 fork() 和调用 exec 函数之间调用需要某些资源的函数的效果是未定义的。

【讨论】:

  • the effects of calling functions that require certain resources between the call to fork() and the call to an exec function are undefined. 你能解释一下这条线是什么意思吗?非常明确的是,此类“中间”函数将具有每个进程的资源和当前线程的资源,但没有与其他线程相关的资源。那么这里的“未定义”是什么?
  • @Mergasov — 作为实例,假设线程 T1 已锁定 stderr(参见 POSIX flockfile()),因为当线程 T2 调用 fork() 时,它正在调用 fprintf(stderr, …) .父进程没有什么特殊问题,但是子进程只有一个线程对应于T2,并且该线程不拥有stderr上的锁。所以,如果孩子需要报错,就会卡住等待释放锁,但永远不会释放锁。这是“某些资源”的一个例子。
猜你喜欢
  • 1970-01-01
  • 2021-06-12
  • 1970-01-01
  • 2021-10-30
  • 1970-01-01
  • 2014-02-08
  • 1970-01-01
  • 2020-03-13
  • 1970-01-01
相关资源
最近更新 更多