Linux C编程连载(8) - 也说fork()

本文详细探讨了使用fork()函数时遇到的问题,包括子进程PID为0的原因、fork()调用一次为何返回两次以及执行过程中的先后顺序。通过结合实际例子,解释了父进程与子进程的创建与返回顺序,强调了堆栈特性对此过程的影响。

【问题描述】

最近使用fork(),有几个问题觉得值得总结一下:

1 为什么子进程pid编号为0?

2 fork()调用一次,返回2次,机理是什么?

3 fork()执行后,先创建子进程,还是父进程?先返回的是子进程,还是父进程?

 

【分析】

1 为什么子进程pid编号为0?

因为子进程可能有多个,不可能返回所有的子进程编号,而父进程只有一个。

 

2 fork()调用一次,返回2次,机理是什么?

由于在复制时,复制了父进程的堆栈段,所以两个进程都停留在fork函数中,等待返回。因为fork函数会返回两次,一次是在父进程中返回,另一次是在子进程中返回,这两次的返回值是不一样的。调用fork之后,数据、堆栈有两份,代码仍然为一份,但是这个代码段成为两个进程的共享代码段,都从fork函数中返回。为什么这样呢?

如果对递归有深入认识,就不难理解了。fork()的调用是运用了堆栈这种数据结构。堆栈是一种先进后出的数据结构。创建父进程后,在返回之前,创建子进程,等待子进程创建完成后,再返回父进程。具体的过程fork()两次不同返回值的实现 讲得比较透彻,此处不再赘述。

 

3 fork()执行后,先创建子进程,还是父进程?先返回的是子进程,还是父进程?

看一个fork()和pipe()结合的例子

#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>

#define MAX_DATA_LEN 256
#define DELAY_TIME 1
#define DEBUG 1

int main()
{
	pid_t pid;
	int pipe_fd[2];
	char buf[MAX_DATA_LEN];	
	const char data[] = "Pipe Test Program";

	int real_read, real_write;
	
	memset((void *)buf, 0, sizeof(buf));

	if(pipe(pipe_fd)<0)
	{
		perror("Pipe");
		exit(1);
	}

	pid = fork();

	if(pid == 0)
	{	

#if DEBUG
		printf("a1\n");
#endif
		close(pipe_fd[1]);
		sleep(DELAY_TIME*3);
#if DEBUG
		printf("a2\n");
#endif	

		if((real_read = read(pipe_fd[0], buf, MAX_DATA_LEN)) >0 )	
		{
			printf("%d bytes read from the pipe is '%s'\n",real_read,buf);
		}
		close(pipe_fd[0]);
	}
	else if(pid > 0)
	{
#if DEBUG
		printf("b1\n");
#endif
		close(pipe_fd[0]);
		sleep(DELAY_TIME);
#if DEBUG
		printf("b2\n");
#endif

		if((real_write = write(pipe_fd[1], data, MAX_DATA_LEN)) != -1 )	
		{
			printf("Parent wrote %d bytes : '%s'\n",real_write,data);
		}
		close(pipe_fd[1]);
		waitpid(pid, NULL, 0);

		exit(0);
	}
	
}

 


运行结果如下:

[tandesir@localhost test]$ ./pipe 
a1
b1
b2
Parent wrote 256 bytes : 'Pipe Test Program'
a2
256 bytes read from the pipe is 'Pipe Test Program'


 

上面的程序如果将DEBUG定义为0,则会给人一种假象,好像是先返回了父进程,再返回子进程。输出如下:

[tandesir@localhost test]$ ./pipe 
Parent wrote 256 bytes : 'Pipe Test Program'
256 bytes read from the pipe is 'Pipe Test Program'


由上述程序,可以证实,先返回的是子进程。

父进程都没有创建,当然不会有子进程。所以先创建父进程。之所有先返回子进程,这是由堆栈的特性决定的。

结论:先创建父进程,后创建子进程。先返回子进程,后返回父进程。

 

【学习参考】

(1) http://baike.baidu.com/view/1952900.htm?fromTaglist

(2) fork()两次不同返回值的实现

(3) fork调用的内核实现

(4) 一个fork的面试题(推荐阅读)

 

 

转载请标明出处,仅供学习交流,勿用于商业目的

Copyright @ http://blog.youkuaiyun.com/tandesir

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值