要了解子进程,了解fork首先要知道什么是进程,具体参见博客linux 什么是进程和进程状态转换、
我首先来看一个程序代码
#include<stdlib.h>
#include<errno.h>
int main()
{
int pid=-1;
int val=20;
pid =fork();//这句话就是我们利用fork创建一个子进程
if(pid<0)
exit(-1);
else if(pid==0)
{
val=1;
sleep(5);
printf("this is child\n");
}
else
{
printf("this is parent\n");
}
while(1)
{
printf("this is public :%d\n",val);
sleep(1);
}
return 0;
}
我们来看一下运行结果:
有没有感觉这像是两个程序交替运行。
id,pid
id,pid,ppid都是用来唯一描述该进程的标识符,可以用来区别其他进程。
父进程叫ppid
子进程叫pid
下面让我们介绍一下fork
看了我们什么是进程的介绍,我们都知道了,每个进程都有它独自占有的PCB结构体,而我们通过fork。就是将进程复制了一份。
1.父进程和子进程是共享一块代码段的,也就是说同样的代码,父进程和子进程个执行一遍。
2.父进程和子进程数据独自占有,不共享。这就是为什么父进程和子进程同样的代码,却打印出两个不同的val值。
3.fork函数很神奇。它有两个返回值,父进程的返回值是子进程的id号,而子进程自己返回则返回零。失败返回-1.所以我们可以通过介绍fork()返回值来区分父进程子进程,还可以在子进程进行一些特殊操作。
vfork()
vfork和fork类似都是创建一个子进程,与父进程共享代码段,不同的是,
1.vfork创建的子进程和父进程共享地址空间,也就是没有数据独享,通过子进程改变的数据,父进程对应数据也会发生改变。
2.vfork还规定子进程先运行,在它调用exec函数或者退出后父进程才可以运行。就是说,子程序没有运行其他程序或者退出前,父进程阻塞在vfork处不向下运行。
exec函数
当子进程调用exec函数来运行另一个程序时,这个进程的地址空间代码和数据都被新程序的代码和数据刷新替换。及进程程序发生了替换。
换言之,就是说,当我们调用exec函数时,并不会创建新的进程,而是换了代码段的段中内容,没有给换段,没有换进程,所以调exec后id号不变。
1.exec函数组的作用是程序替换,如果替换成功则即将运行的代码段的内容已经不是以前的代码段的内容了,而是新程序,因此原来代码中位置在exec函数以后的代码不会运行,除非出错,不然没有执行的可能。因为代码段被替换,因此在替换以后的原代码都不会被执行,因为代码段里已经没有这些代码了。
2.程序替换只是替换代码段,初始化了数据区域,因此程序替并不会重新创建虚拟地址空间,和页表。也是替换了其中的内容。
3.替换后这个进程将从入口函数开始运行。
4.所以只有调用exec函数失败时,才有返回值,成功就没有返回。
exec函数组介绍
execl :参数1:要执行文件的路径,这个路径必须是绝对路径 ,参数2: 这个参数代表执行该文件时传递的参数列表:argv[0],argv[1]… 最后一个参数须用空指针NULL作结束。
execlp:不需要给出文件的全路径,给出文件名,系统会自动搜索路径查找
execle:execle需要用户自己组织环境变量,而execl却是继承父进程的全部环境变量,具体参见博客linux中环境变量
execv:execv的参数传递,是通过一个字符串数组,直接传过去的,而execl是把个命令展开,一个一个传过去的。
样例如下: