当使用fork创建子进程采用写时拷贝,所以在任何一个进程不发生变化的情况下,它们都是共享虚拟内存空间的代码段和数据段,但是如果一方发生变化,那么就需要重新复制一份虚拟内存空间,供发生变化的一方进行修改。就比如程序替换,正因为fork之后子进程和父进程代码完全相同,但是我们可能需要让子进程和父进程执行不同的代码,所以就有了程序替换。程序替换原理就是修改程序的代码段和数据段,所以当发生程序替换的时候,子进程的代码段和数据段通过页表映射到了另外的物理地址。
程序替换之后子进程和父进程虚拟内存空间中的内核空间和环境变量至少还是共享的。
1.为什么要有程序替换
使用fork创建进程之后,子进程和父进程执行相同的代码,但是在实际开发当中,我们希望父子进程执行不同的代码,提高开发效率,所以就有了程序替换。
2.替换原理
把代码和数据替换为可执行文件的代码和数据,但是环境变量不会发生改变。程序替换并不创建子进程,所以就不会有PCB的拷贝,当然id也没有发生变化。程序替换使用一种exec函数以执行另外一个程序,当进程调用exec函数时,该进程的代码和数据完全被替换为新的可执行程序(当然替换的是exec之后的代码和数据)。所以,可以推断出exec函数没有成功返回值,只有失败返回值-1。
3.替换函数
程序替换函数exec主要有6个:见下图
4.命名理解
(1)l (list):采用参数列表方式也就是命令行参数形式;
(2)v (vector):参数使用数组;
(3)p (path):含有p的自动搜索环境变量PATH;
(4)e (env):需要自己维护环境变量;
5.具体实例
// exec.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
char *env[] = {
"AAAA=aaa",
NULL
};
char *const argv_1[] = {
"ls",
"-l",
NULL
};
char *const argv_2[] = {
"test",
NULL
};
//int ret = execl("/use/bin/ls","ls","-l",NULL);
//int ret = execlp("ls","ls","-l",NULL);
//int ret = execle("./test","./test",NULL,env);
//int ret = execv("/usr/bin/ls",argv_1);
//int ret = execvp("ls",argv_1);
//int ret = execve("./test",argv_2,env);
if(ret<0)
{
perror("exec");
exit(1);
}
return 0;
}
// test.c
#include<stdio.h>
#include<stdlib.h>
int main()
{
printf("env:%s\n",getenv("AAAA"));//获取一个环境变量
return 0;
}