进程学习(一)——fork()和vfork()函数学习过程

fork()函数:

头文件:#include <unistd.h>
函数原型:pid_t for(void);
fork()函数用于派生出另一个进程,原有的进程成为父进程,新生成的进程成为子进程。父进程调用fork后返回值是子进程的ID,子进程调用fork后返回值是0,调用出错时,返回值为-1.下面看个fork函数创建进程的例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void) {
	pid_t pid;
	printf("PID before fork():%d\n", getpid());
	
	pid = fork();
	if (pid == 0)
		printf("This is the child process.my PID:%d,parentPID:%d\n",\
				pid, getpid());
	else if(pid > 0)
		printf("This is the parent process.my PID:%d,childPDI:%d\n",\
				getpid(), pid);
	else {
		printf("fork error.\n");	
		exit(1);
	}
	return 0;
}

从测试结果可以看出,印证了我们上面说的,父进程返回的是子进程ID,子进程返回的是0.

刚开始学习进程的时候,一直不理解进程的运行过程到底是怎样的。不清楚fork函数的作用,第一篇参考资料的那个例子让我理解的比较清楚了:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void) {
	pid_t pid;
	int count = 0;
	pid = fork();

	printf("This is first,PID:%d.\n", pid);
	count++;
	printf("count=%d\n", count);

	if (pid < 0) {
		printf("fork failed.\n");	
		exit(1);
	}
	else if (pid == 0)
		printf("this is the child process.\n");
	else
		printf("this is the parent process.child PID:%d.\n", pid);

	printf("this is second,PID:%d.\n", pid);

	return 0;
}


实际上调用fork函数后分裂出了两个进程,而且它们分别执行互不干扰。一般情况下调用fork函数后父子进程谁先执行是未定的,取决于内核所使用的调度算法。从程序的结果就可以看出来,调用fork函数的部分确实执行了两遍,但是count的值一直都没有改变,这是因为父进程和子进程是分别执行的。

vfork()函数

头文件:#include <unistd.h>
函数原型:pid_t vfork(void);
vfork函数也是创建进程的,但是它实际上也是调用了fork函数。调用vfork与调用fork的作用基本相同,但是差别还是挺大的。先看看下面两个例子:
例子1:调用fork函数
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int globalVal = 5;

int main(void) {
	pid_t pid;
	int val = 1, i;

	pid = fork();
	if (pid == 0) {
		i = 3;
		while (i-- > 0) {
			printf("child process is running.\n");	
			globalVal++;
			val++;
			sleep(1);
		}
		printf("child's globalVal = %d, val = %d.\n", globalVal, val);
	}
	else if (pid > 0) {
		i = 5;
		while (i-- > 0) {
			printf("parent process is running.\n");
			globalVal++;
			val++;
			sleep(1);
		}
		printf("parent glovalVal = %d, val = %d.\n", globalVal, val);
	}
	else {
		printf("fork failed.\n");	
		exit(1);
	}
	return 0;
}

测试结果:


例子2:调用vfork函数
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int globalVal = 5;

int main(void) {
	pid_t pid;
	int val = 1, i;

	pid = vfork();
	if (pid == 0) {
		printf("子进程开始了!!!\nn");

		i = 3;
		while (i-- > 0) {
			printf("child process is running.\n");	
			globalVal++;
			val++;
			sleep(1);
		}
		printf("child's globalVal = %d, val = %d.\n", globalVal, val);

		printf("子进程结束了!!!\nn");
		exit(0);
	}
	else if (pid > 0) {
		printf("父进程开始了!!!\n");

		i = 5;
		while (i-- > 0) {
			printf("parent process is running.\n");
			globalVal++;
			val++;
			sleep(1);
		}
		printf("parent glovalVal = %d, val = %d.\n", globalVal, val);
		
		printf("父进程结束了!!!\n");
	}
	else {
		printf("fork failed.\n");	
		exit(1);
	}

	return 0;
}



测试结果:


从两个程序的测试结果可以看出几点区别来:
  • 调用vfork时,父进程被挂起,子进程运行完exec函数簇的函数或调用exit时解除父进程的挂起状态(要不然会进入死循环,开始我就是按照第一篇资料里那样,在子进程和父进程结束的后面什么都没有加结果进入死循环了,资料里是在父进程结束时调用了exit(0)个人感觉不是这样的,因为正常的情况是先执行子进程然后执行exit(0)结束子进程,接着就会执行父进程,然后父进程执行完了以后就会正常结束程序)。
  • vfork和fork还有一点不同的就是,调用vfork生成的子进程并不完全复制父进程的数据段,而是和父进程共享数据段。所以globalVal和val变量在子进程之后得到的值,进入父进程继续增加。
  • 调用vfork对于父进程的执行次序还是有限制的。

vfork和for分别与exec函数簇

看了些资料,上面都说vfork函数通常是与exec函数簇一起使用的,用来创建执行另一个程序的新进程。由于数据共享的原因fork创建的进程只是父进程的一个副本,也可以利用exec函数在子进程中重新载入一个全新的进程,下面看看fork和vfork分别与exec结合的例子
例子1:fork与exec
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(void) {
	pid_t pid = fork();
	switch(pid) {
	case 0:
		printf("子进程\n");
		execl("/bin/ls", "ls", "-l", NULL);
		break;
	case -1:
		printf("fork失败\n");
		exit(1);
		break;
	default:
		wait(NULL);
		printf("完成了\n");
		exit(0);
		break;
	}
	return 0;
}

测试结果:


例子2:vfork与exec函数
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(void) {
	pid_t pid = vfork();
	if (pid == 0) {
		printf("This is the child process.\n");	
		execl("/bin/ls", "ls", "-l", NULL);
	}
	else if (pid > 0) {
		wait(NULL);
		printf("This is the parent process.\n");
	}
	else {
		printf("vfork failed\n");	
		exit(1);
	}

	return 0;
}

测试结果:



参考资料:
http://www.360doc.com/content/11/0411/19/6580811_108904985.shtml
http://www.cnblogs.com/codebean/archive/2011/06/06/2073609.html

猜你喜欢

转载自blog.csdn.net/u011248694/article/details/28853413