在创建进程时,会用到fork 或vfork 创建子进程
1)copy- on write(fork)
fork之后exec之前,父子进程的虚拟空间不同,但其对应的物理空间是同一个!
两个进程用的是相同的物理空间(内存区),子进程的代码段、数据段、堆栈都是指向父进程的物理空间! (从左往右的大箭头表示的创建子进程的复制动作)
当父子进程中有更改相应段的行为发生时,再为子进程相应的段分配物理空间!
如果是在子进程中调用了exec,由于两者执行的代码不同,子进程的代码段也会分配单独的物理空间。
fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序,当进程调用一种exec函数时,该进程完全由新程序代换,而新程序则从其main函数开始执行,因为调用exec并不创建新进程,所以前后的进程id 并未改变,exec只是用另一个新程序替换了当前进程的正文,数据,堆和栈段。
2 ) vfork
1 vfork 不会将父进程的地址空间完全复制到子进程中,也不会复制页表。在子进程调用ecec 或者exit的之前,子程序会在父程序的空间运行,父进程阻塞。挂起)
2 vfork保证子进程先运行(fork不能保证),在她调用exec或exit之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。(从左到右的箭头表示的是共享)
///
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int glob = 6;
int main()
{
int var;
pid_t pid;
var = 88;
printf("before fork\n");
if((pid = fork()) < 0)
{
perror("fork");
return 1;
}
else if(pid == 0)// 子进程
{
glob++;
var++;
_exit(0);
}
else // 父进程
{
printf("pid=%d,glob=%d,var=%d\n", getpid(),glob,var);
exit(0);
}
}
/*
fork时,由于glob 和 val 没有发生变化 ,说明父子进程在数据发生改变时,会独立分配给子进程一块儿物理空间。
vfork 两个数据发生了改变,表示子进程在父进程空间中运行。
*/
结果:
before fork
father process pid=4681,glob=6,var=88
son process pid=4682,glob=7,var=89
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int glob = 6;
int main()
{
int var;
pid_t pid;
var = 88;
printf("before vfork\n");
if((pid = vfork()) < 0)
{
perror("vfork");
return 1;
}
else if(pid == 0)// 子进程
{
glob++;
var++;
printf("son process pid=%d,glob=%d,var=%d\n", getpid(),glob,var);
_exit(0);
}
else // 父进程
{
printf("father process pid=%d,glob=%d,var=%d\n", getpid(),glob,var);
exit(0);
}
}
结果:
before vfork
son process pid=4670,glob=7,var=89
father process pid=4669,glob=7,var=89