fork,写时复制(copy-on-write),vfork
进程创建
进程创建分为三种情况
1.共享
父进程与子进程共享数据段、堆栈段、代码段,也就是说子进程对数据进行的改变会直接影响父进程。
2.写时复制(Copy-On-Write)
我简单地将这种技术理解为,当子进程执行写操作时,内核会将被修改的部分单独copy,单独操作。
3.直接拷贝
直接复制父进程的数据段、堆栈段,共享代码段。
一、fork
fork()调用时,子进程会复制父进程数据段、堆栈段,并且使用新的物理地址以及虚拟地址存储。但父子进程共享代码段。但现在的实现采用了写时复制技术。
二、vfork
vfork()调用时,父子进程共享所有资源。但在调度上,使用vfork将保证子进程先于父进程被调度。
下面给出参考书的代码用以说明两者区别:
- fork
/**********************************************************************
> File Name: t_fork.c
> Author: 0nism
> Email: fd98shadow@sina.com
> Created Time: Sun 14 Oct 2018 02:41:39 PM CST
***********************************************************************/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
static int idata = 111; // Allocated in data segment
int main(int argc, char **argv)
{
int istack = 222; // Allocated in stack segment
pid_t childPid;
switch (childPid = fork())
{
case -1:
printf("err: fork\n");
return 0;
case 0:
idata *= 3;
istack *= 3;
break;
default:
sleep(3);
break;
}
printf("PID=%ld %s idata=%d istack=%d\n", (long)getpid(),
(childPid == 0) ? "child " : "parent ", idata, istack);
exit(EXIT_SUCCESS);
}
运行结果为
MISlike@10:56:~/process $ ./t_fork
PID=5566 child idata=333 istack=666
PID=5565 parent idata=111 istack=222
无论是数据段还是堆栈段均完成了复制。
- vfork
/**********************************************************************
> File Name: t_vfork.c
> Author: 0nism
> Email: fd98shadow@sina.com
> Created Time: Sun 14 Oct 2018 11:21:22 PM CST
***********************************************************************/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int istack = 222;
switch (vfork())
{
case -1:
printf("err: vfork\n");
return 0;
case 0: // 子进程优先执行,在父进程的虚拟地址空间中
sleep(3); // 即使休眠一段时间,父进程仍然不会先执行
write(STDOUT_FILENO, "Child excuting\n", 16);
istack *= 3; // 这个变化将会被父进程知晓
_exit(EXIT_SUCCESS);
default: // 父进程被锁住直到子进程消亡
write(STDOUT_FILENO, "Parent excuting\n", 16);
printf("istack = %d\n", istack);
_exit(EXIT_SUCCESS);
}
}
运行结果如下
Child excuting
Parent excuting
istack = 666
可见子进程操作影响到了父进程,且此时父进程被阻塞,知道子进程消亡或者执行excu()。