我正在将Windows应用程序移植到Linux。我在Windows上使用CreateProcess
来运行子进程并重定向所有标准流(in,out,error)。流重定向很关键,主进程将数据发送给子进程并接收他们的输出和错误消息。主进程非常大,具有大量内存和线程,子进程是小进程。在Linux上,我看到fork
函数在Windows上具有与CreateProcess
类似的功能。但是,手动说fork
“创建父进程副本”,包括代码,数据和堆栈。这是否意味着如果我创建一个使用1 GB内存的巨大进程的副本只是为了运行一个使用1 MB内存的非常简单的命令行工具,我将需要与{{1}重复1 GB的内存,然后用1 MB进程替换此1 GB?那么,如果我有100个线程,它将需要100 GB的内存来运行100个需要100 MB内存才能运行的进程?另外,父进程中其他线程“不知道”关于fork
执行,他们会做什么? fork
函数的作用是什么?“它是从巨大的父母创建大量小子进程的真正有效方法吗?
答案 0 :(得分:8)
当您致电fork()
时,最初只会复制您的VM,并且所有页面都会被标记为copy-on write。您的新子进程将具有父进程VM的逻辑副本,但在您实际开始写入之前它不会消耗任何额外的RAM。
对于线程,fork
在子进程中只创建一个类似于调用线程副本的新线程。
此外,只要您调用任何exec
系列调用(我假设您想要),您的整个过程映像就会被替换为新映像,并且只保留文件描述符。
如果您的父进程有很多打开的文件描述符,那么我建议您浏览/proc/self/fd
并关闭您不需要的子进程中的所有文件描述符。
答案 1 :(得分:3)
fork
基本上将您的进程拆分为两个,父进程和子进程在fork
函数调用之后继续执行指令。但是,子进程中的返回值为0,而在父进程中,它是子进程的进程ID。
子进程的创建非常快,因为它使用与父进程相同的页面。页面标记为写入时复制(COW),因此,如果任一进程更改页面,则另一个不会受到影响。一旦子进程存在,它通常会调用其中一个exec
函数来替换自己的图像。 Windows与fork
没有等效,而CreateProcess
调用只允许您启动新流程。
fork
有一个名为clone的替代方案,可以让您更好地控制新流程启动时会发生什么。例如,您可以指定要在新流程中调用的函数。
答案 2 :(得分:2)
副本是“copy-on-write”,因此如果您的子进程不修改数据,它将不会使用除父进程之外的任何内存。通常,在fork()
之后,子进程使exec()
用另一个进程替换此进程的程序,然后无论如何都会丢弃所有内存。
答案 3 :(得分:1)
我没有使用CreateProcess
,但fork()
并不是该过程的精确副本。它创建了一个子进程,但是子进程在父进程名为fork
的相同指令处开始执行,并从那里继续执行。
我建议您查看Chapter 5操作系统手册的Three Easy Pieces。这可能会让你开始,你可能会找到你正在寻找的孩子产卵电话。
答案 4 :(得分:1)
分叉的子进程已经几乎复制了所有父工具:内存,描述符,文本等。唯一的例外是父代的线程,它们不会被复制。