http://www.cnblogs.com/leoo2sk/archive/2009/12/11/talk-about-fork-in-linux.html
http://www.cnblogs.com/jimwind/archive/2012/12/26/2834147.html
http://www.cnblogs.com/hicjiajia/archive/2011/01/20/1940154.html
Linux下一个进程在内存里有三部分的数据,就是"代码段"、"堆栈段"和"数据段"。其实学过汇编语言的人一定知道,一般的CPU都有上述三种段寄存器,以方便操作系统的运行。这三个部分也是构成一个完整的执行序列的必要的部分。
"代码段",顾名思义,就是存放了程序代码的数据,假如机器中有数个进程运行相同的一个程序,那么它们就可以使用相同的代码段。"堆栈段"存放的就是子程序的返回地址、子程序的参数以及程序的局部变量。而数据段则存放程序的全局变量,常数以及动态数据分配的数据空间(比如用malloc之类的函数取得的空间)。这其中有许多细节问题,这里限于篇幅就不多介绍了。系统如果同时运行数个相同的程序,它们之间就不能使用同一个堆栈段和数据段。
1、fork 创建一个子进程,有两个返回值。返回0为子进程,返回大于0为父进程。
fork函数启动一个新的进程,前面我们说过,这个进程几乎是当前进程的一个拷贝:子进程和父进程使用相同的代码段;子进程复制父进程的堆栈段和数据段。这样,父进程的所有数据都可以留给子进程,但是,子进程一旦开始运行,虽然它继承了父进程的一切数据,但实际上数据却已经分开,相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。它们再要交互信息时,只有通过进程间通信来实现,这将是我们下面的内容。既然它们如此相象,系统如何来区分它们呢?这是由函数的返回值来决定的。对于父进程, fork函数返回了子程序的进程号,而对于子程序,fork函数则返回零。
2、exec 运行新的可执行文件,取代原调用进程的数据段、代码段和堆栈段。一般是运行fork后,在子进程中执行exec。
我们来看看一个进程如何来启动另一个程序的执行。在Linux中要使用exec函数族。系统调用execve()对当前进程进行替换,替换者为一个指定的程序,其参数包括文件名(filename)、参数列表(argv)以及环境变量(envp)。exec函数族当然不止一个,但它们大致相同,在 Linux中,它们分别是:execl,execlp,execle,execv,execve和execvp,下面我只以execlp为例,其它函数究竟与execlp有何区别,请通过manexec命令来了解它们的具体情况。
一个进程一旦调用exec类函数,它本身就"死亡"了,系统把代码段替换成新的程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过已经是另一个程序了。(不过exec类函数中有的还允许继承环境变量之类的信息。)
一起使用的一个例子
1#include <errno.h> 2#include <stdio.h> 3#include <stdlib.h> 4 5char command[256]; 6void main() 7{ 8 int rtn; /*子进程的返回数值*/ 9 while(1) { 10 /* 从终端读取要执行的命令 */ 11 printf( ">" ); 12 fgets( command, 256, stdin ); 13 command[strlen(command)-1] = 0; 14 if ( fork() == 0 ) {/* 子进程执行此命令 */ 15 execlp( command, NULL ); 16 /* 如果exec函数返回,表明没有正常执行命令,打印错误信息*/ 17 perror( command ); 18 exit( errno ); 19 } 20 else {/* 父进程, 等待子进程结束,并打印子进程的返回值 */ 21 wait ( &rtn ); 22 printf( " child process return %d\n", rtn ); 23 } 24 } 25}