调用fork时是否复制线程?


31

如果我有一个运行线程的程序并fork()在基于UNIX的系统上调用,是否复制了线程?我知道当前进程的虚拟内存将1:1复制到新进程。我知道线程在进程的虚拟内存中有自己的堆栈。因此,至少也应该复制线程堆栈。但是,我不知道线程中是否还有其他不驻留在虚拟内存中并且因此不会被复制的线程。如果没有,这两个进程是共享线程还是它们是独立副本?

Answers:


29

没有。

线程不会复制到fork()。POSIX规范说(强调是我的):

fork-创建一个新过程

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

为了解决这个问题,存在一个pthread_atfork()帮助功能。


7

人叉

子进程由一个线程创建,该线程称为fork()。父级的整个虚拟地址空间都在子级中复制,包括互斥体,条件变量和其他pthreads对象的状态;使用pthread_atfork(3)可能有助于解决可能引起的问题。


但这似乎很奇怪:如果实际的线程(我不知道包含虚拟内存以外的其他存储空间)没有,为什么要复制进程调用fork中的线程堆栈?

那么为什么它是一个完全不同的问题。我不知道导致该实现的原始设计决策。如果您有兴趣,则应单独回答。
kaylum

@dip但未复制其他线程堆栈,谁这么说?
Jean-BaptisteYunès

1
@Jean-BaptisteYunès在unix系统中,有一个表示进程虚拟内存的结构。那就是复制的那个。不只是堆和bss

6
您可以获得整个内存空间-因此获得了所有线程的堆栈。你需要的,因为有在哪里住在堆(或静态存储器)访问剩余的线程中的指针指向没有限制-他们很可能会指向的是住在某个线程在原有的工艺堆栈数据
davidbak

4

摘自The Open Group Base Specification第7期,2018年版的分支

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

当应用程序从信号处理程序调用fork()时,并且pthread_atfork()注册的任何fork处理程序调用的函数都不是异步信号安全的,该行为是不确定的。


-2

最初,“分叉”是通过将任务写入磁盘,然后读取而不是读入其他线程(如果将任务换为其他线程来完成),修改仍在内存中的映像的任务ID并继续执行来实现的及其执行(作为新任务)。这是对基本任务切换机制的非常简单的修改,其中一次仅一个任务会占用RAM内存。

当然,随着内存管理的不断完善,该方案也进行了修改以适应新环境。


好奇为什么这被否决了。Unix就是这样做的。
热舔

这是一个有趣的见解,但是它在哪里提到线程?看起来不像是我的答案。
wastl
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.