fork,写时复制(copy-on-write),vfork

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
");
					return 0;

			case 0:
					idata *= 3;
					istack *= 3;
					break;

			default:
					sleep(3);
					break;
		}   

		printf("PID=%ld %s idata=%d istack=%d
", (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
");
					return 0;

			case 0:                 //  子进程优先执行,在父进程的虚拟地址空间中
					sleep(3);       //  即使休眠一段时间,父进程仍然不会先执行

					write(STDOUT_FILENO, "Child excuting
", 16);
					istack *= 3;    //  这个变化将会被父进程知晓
					_exit(EXIT_SUCCESS);

			default:                //  父进程被锁住直到子进程消亡
					write(STDOUT_FILENO, "Parent excuting
", 16);
					printf("istack = %d
", istack);
					_exit(EXIT_SUCCESS);

		}   
	}

运行结果如下

Child excuting
Parent excuting
istack = 666

可见子进程操作影响到了父进程,且此时父进程被阻塞,知道子进程消亡或者执行excu()。

原文地址:https://www.cnblogs.com/0nism/p/9789862.html