fork()
用fork()系统调用创建(复制)一个继承的子进程
- 复制父进程所有的变量和内存;
- 复制父进程的所有CPU寄存器(有一个寄存器除外,记录不同进程ID)
- 子进程的fork()会返回0,父进程的返回进程标识符,子进程可以使用getpid()来获取pid;
示例如下:
int pid == fork();//创建子进程
if(pid == 0){
//子进程运行区域
}
//父进程运行区域
在子进程运行区域中可以调用exec()系统调用来加载新进程取代当前运行进程,示例:
int pid == fork();//创建子进程
if(pid == 0){
exec_status = exec("calc",argc,argc0,...);
//这一句指定了可执行的程序和具体的参数
}
//父进程运行区域
这个加载过程会把复制的之前进程的地址空间中的代码、堆栈信息全部替换掉,内核中除了ID不变,其他的也换掉。
fork()的开销问题
正如前面说的fork()的任务是复制父进程的地址空间、内存和它的寄存器状态。所以开销很大。
事实上在99%的情况下,我们在调用了fork()后调用exec(),那么:
- 在fork()操作中内存复制就没有必要了,这部分我们可以不做;
- 子进程可能关闭父进程打开的文件和连接;
- 所以windows中的做法是用一个系统调用同时完成创建和加载;
- 在早期的unix中,用vfork(),在创建的时候不进行复制,等到用的时候再直接进行加载,这个不必要的复制就可以省掉。(又称为 轻量级fork)
- 现在一般使用写时复制技术(Copy on write)COW技术。