【Linux】fork

概述

在Linux系统中 创建进程有两种方式:一是由操作系统创建,二是由父进程调用函数fork()创建进程(通常为子进程)

fork相当于把父进程复制了一份,以32位系统为例,进程的虚拟地址空间是从0到4G的大小,其中0-3G是用户空间,3-4G是内核空间。创建完子进程后,父进程继续运行后续的代码,刚创建出来的子进程拥有和父进程完全一样的代码段,数据段,也就是说完完全全拷贝了一份父进程,和父进程完全一样。即clone父进程0-3G的用户空间内容,而3-4G的kernel只需要重新映射一下到物理地址的kernel即可。

既然是复制出来的,那如何区分这两个进程呢?答案就是进程ID,即pid。fork函数被调用一次将返回两次,在子进程中返回0,在父进程中返回子进程的pid
所以,在调用fork之后,接下来的代码要根据fork返回的pid去区分进程,让父进程接着干原来的事,子进程去干新的事情。

fork的写时拷贝(copy-on-write)

  • fork出来的进程大部分情况下会执行一个新的任务,可能并不关心fork之前的数据,如果直接把所有的资源复制给新创建的进程。这种实现过于简单并且效率低下,会浪费很多资源,所以Linux的fork()使用写时拷贝(copy-on-write)页实现。
  • 写时拷贝是一种可以推迟甚至避免拷贝数据的技术。内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。只用在需要写入的时候才会复制地址空间,从而使各个进行拥有各自的地址空间。也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享。