Linux 为什么fork()是这样工作的

Linux 为什么fork()是这样工作的,linux,process,fork,Linux,Process,Fork,因此,我使用了fork(),我知道它的作用。作为一个初学者,我非常害怕它(我仍然不完全理解它)。您可以在线找到的fork()的一般描述是,它复制当前进程并分配不同的PID、父PID,进程将具有不同的地址空间。所有这些都是好的,但是,鉴于这个功能描述,初学者可能会想“为什么这个功能如此重要……为什么我要复制我的流程?”。所以我很好奇,最终我发现这就是如何通过execve()家族从当前进程中调用其他进程的方法 我仍然不明白的是你为什么要这样做?最合乎逻辑的事情是拥有一个可以像这样调用的函数 crea

因此,我使用了
fork()
,我知道它的作用。作为一个初学者,我非常害怕它(我仍然不完全理解它)。您可以在线找到的
fork()
的一般描述是,它复制当前进程并分配不同的PID、父PID,进程将具有不同的地址空间。所有这些都是好的,但是,鉴于这个功能描述,初学者可能会想“为什么这个功能如此重要……为什么我要复制我的流程?”。所以我很好奇,最终我发现这就是如何通过
execve()
家族从当前进程中调用其他进程的方法

我仍然不明白的是你为什么要这样做?最合乎逻辑的事情是拥有一个可以像这样调用的函数

create_process("executable_path+name",params..., more params); 
这将产生一个新进程,并在main()的开头开始运行它,然后返回新的PID

让我感到困扰的是,fork/execve解决方案正在做可能不需要的工作。如果我的进程使用了大量内存怎么办?内核是否复制我的页面表等。我确信它不会真正分配真正的内存,除非我触摸过它。还有,如果我有线程会发生什么?我只是觉得太乱了

几乎所有关于fork的描述都是这样的,比如说它只是复制进程,新进程在
fork()
调用之后开始运行。这确实是发生的事情,但为什么它会以这种方式发生,为什么fork/execve是生成新进程的唯一方式,从当前进程创建新进程的最通用的unix方式是什么?是否有其他更有效的方法生成进程?**不需要复制更多内存

thread也谈到了同样的问题,但我觉得它不太令人满意:


谢谢。

就分页/虚拟内存而言,有些技术使用fork()并不总是复制进程的整个地址空间。有一种写时复制,即分叉进程获得与其父进程相同的地址空间,然后只复制(通过任一进程)更改的部分空间。

请看一看,朋友们。

记住,
fork
是在Unix中很早就被发明的(可能是以前),在今天看来小得可笑的机器上(例如64K字节的内存)

它更符合通过最基本的可能行动提供基本机制而不是政策的总体(原始)理念

fork
只是创建了一个新的进程,最简单的思维方式就是克隆当前进程。因此
fork
语义非常自然,是可能的最简单机制

其他系统调用(
execve
)负责加载新的可执行文件等

将它们分开(并提供
管道
dup2
系统调用)提供了很大的灵活性

在当前系统上,
fork
的实现效率非常高(通过写时延迟复制分页技术)。众所周知,
fork
机制使Unix进程创建速度非常快(例如,比Windows或VAX/VMS更快,后者的系统调用创建的进程更类似于您所建议的进程)

还有一个系统调用,我不用它


而且API比单独的
fork
execve
复杂得多,因此说明
fork
更简单…

fork
通过复制当前进程创建新进程时,它会在写入时执行复制。这意味着新进程的内存将与父进程共享,直到被复制为止nged。当更改内存时,会复制内存,以确保每个进程都有自己的有效内存副本。当在
fork
ing之后立即执行
execve
时,没有内存副本,因为新进程只加载一个新的可执行文件,从而加载一个新的内存空间


至于为什么要这样做的问题,我不确定,但这似乎是Unix方式的一部分——做好一件事。与其创建一个创建新进程并加载新可执行文件的函数,不如将该操作分为两个函数。这给了开发人员最大的灵活性。尽管我没有单独使用这两个函数等。

假设底层实现使用写时拷贝寻址系统,则fork()可以用很少的内存分配来实现。不可能用这种优化来实现create_进程函数。

“fork()”是一项杰出的创新,用一个API解决了一整类问题。它是在多处理不常见的时候发明的(比我们今天使用的多处理早了大约二十年)。

使用fork的主要原因是执行速度

如果按照您的建议,使用一组参数启动流程的新副本,则新流程将需要解析这些参数,并重复父流程已完成的大部分处理父进程堆栈的完整副本立即可供子进程使用,所有内容都应按原样进行解析和格式化


此外,在大多数情况下,程序将是一个“.so”或“.dll”,因此不会复制可执行指令,只会复制堆栈和堆存储。

因此,正如其他人所说,
fork
实现得非常快,所以这不是一个问题。但是为什么不使用类似
create\u process()的函数呢
?答案是:简单灵活。unix中的所有系统调用都被编程为只做一件事。像
create\u process
这样的函数可以做两件事:创建一个进程并将二进制文件加载到该进程中

无论何时尝试并行化,都可以使用线程或使用
fork()打开的进程