目录
进程虚拟地址空间
虚拟地址
在学习进程程序替换之前我们先来了解一下进程虚拟地址空间,这样有利于理解进程替换。先来看下面一段代码:
这段代码看起来很奇怪,子进程和父进程打印出来的g_a地址相同,值却不同。我们的理解一直是同一块地址的数据不可能不一样,其实并没有错,那么问题出在哪里?其实在我们看到的地址并不是真真实的地址,在Linux中这种地址称为虚拟地址!操作系统负责将虚拟地址转化成真正的物理地址。
操作系统会给每一个进程分配4G的虚拟内存(32位操作系统),这些虚拟内存并不保存数据,当需要保存数据时,才分配真正的物理内存,通过页表进行映射,如下图:
写时拷贝
当父进程使用fork()创建出子进程时,内核做:
通常情况下,父子进程代码共享,数据共享,当任意一方试图写入,便以写时拷贝的方式各自一份副本。
进程程序替换
替换原理
替换函数
1.execl
就接下来姐可以测试这个函数了:
代码执行后的现象说明此时进程程序替换成功。
2.execlp
代码测试:
可以看到此时没有带路径,也成功了。为什么此时不带路径也可以替换成功呢?
PATH环境变量中有/usr/bin/这个路径。
3. execle
这个函数比execl多了一个参数envp[],它的意思是:调用该函数时需要自己组织环境变量 ,其他参数和execl一样。来看以下代码:
以上代码的作用是获取获取环境变量PATH。此时我们来测试execle()函数:
解释一下environ:每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串 ,environ指向数组第一个元素。,如下图:
如果把test.c中的代码做出以下更改:
那么进程替换到执行get_env时就会执行失败,这是因为将get_env本来的环境变量替换为了NULL,这样getenv()函数就拿不到相应的值了。
所以:在使用execle()时需要自己组织环境变量。
4.execv
此函数的第二个参数是一个字符指针数组, 意思就是将命令行参数组织成字符指针数组的形式,然后进行参数传递。如下代码:
可以发现这个函数和execl()函数的不同点就是把缺省参数改成了字符指针数组。
5.execvp
这个函数和execlp()的不同点就是将缺省参数改成了字符指针数组。
6.execve
这个函数和execle()的不同点就是将缺省参数改成了字符指针数组。
子进程进行程序替换
学习完了以上函数,我们试着使用子进程来进行进程程序换,父进程等待子进程。代码如下:
运行结果如下:
说明子进程进程程序替换成功。