🎁个人主页:我们的五年****
🔍系列专栏:Linux课程学习****
🌷追光的人,终会万丈光芒
🎉欢迎大家点赞👍评论📝收藏⭐文章
目录
推荐书籍:
《深入理解计算机系统》《程序员的自我修养》
1.理解子进程去调用替换函数,达到我们想要的目的。shell命令行也是这样进行处理,我们每次操作的命令,都是fork()创建子进程,然后让子进程调用exe函数进行程序替换,去执行我们想要的程序。比如ls......这些都是一些执行对应程序。
2.进程替换没有创建新进程,所以调用替换函数的进程的pid不会发生变化。
3.程序替换函数只要成功,就会会发生代码替换,就不会有返回值。如果有返回值,就表示程序替换失败。
替换原理:
当一个程序调用exe类型的函数时,这个进程的用户空间代码和数据完全被新进程替换。
从新程序的启动历程开始执行。(C/C++从mian函数开始执行)
exe程序替换函数一般是子进程进行调用。
调用exe类型的函数不会创建新进程,调用exe函数的进程pid不会改变。
替换函数:
程序替换函数以exe开头,所以统称为exe函数。
这些函数包含在头文件:
#include <unistd.h>
命名理解:
●l(list):表示参数采用链表。
●v(vector):采用数组。
●p(PATH):有p表示自动搜索环境变量PATH。
●e(env):表示自己维护环境变量。
命令:
在/usr/bin中放置的就是命令的可执行文件。
6个exe函数
1.execl函数
函数原型:
int execl(const char* path,const char* arg,...);
函数解释:
1.三个点表示可变参数列表,可以传多个参数。
2.path表示要替换程序的路径。(在哪里)
3.后面的arg表示什么样的命令执行。(怎么执行)
实例:
--color表示带颜色显式,这里有两个-。
也可以执行自己的路径,执行自己的可执行程序。
#include <unistd.h>
#include <iostream>
int main()
{
int a=execl("/usr/bin/ls","ls","-l","-a","--color",nullptr);
//如果打印了a的值就表示替换失败
std::cout<<a<<std::endl;
return 0;
}
2.execv函数
函数原型:
int execv(const char* path,char* const argv[]);
函数解释:
1.把这个和1号函数进行比较,唯一的区别就是后面不一样:
execv传递的是一个char* const的数组,而execl传递的是一个个const char*。
v像vector,表示数组。l像list表示的链表,链表就是分别传参。
2.这两个函数没有本质区别,底层都是调用execve。他们就只有传参的不一样,execl调用execve后,传递的每个const char*会变成一个char*数组。
3.后面的几个函数都只有参数不同,底层都调用execve。设计这么多函数是为了满足不同场景的需求,有时候就是要一个一个传参,有时候就有char*数组。
示例:
3.execlp和execvp
函数原型:
int execlp(const char* file,const char* arg,...);
int execlp(const char* file,char* const argv[]);
这两个函数都是带p的,就不要写路径。
#include <unistd.h>
#include <iostream>
int main()
{
//int a=execl("/usr/bin/ls","ls","-l","-a","--color",nullptr);
//int a=execl("./myprocess","./myprocess",nullptr);
pid_t id=fork();
if(id==0)
{
char* const argv[]={
(char*)"ls",
(char*)"-l",
(char*)"-a",
(char*)"--color",
nullptr
};
//int a=execv("/bin/ls",argvs);
// int a=execlp("ls","ls","-l","-a","--color",nullptr);
int a=execvp("ls",argv);
//如果打印了a的值就表示替换失败
std::cout<<a<<std::endl;
exit(1);
}
pid_t pid=waitpid(id,nullptr,0);
if(pid>0)
{
std::cout<<"等待进程成功!"<<std::endl;
}
else if(pid<0)
{
std::cout<<"等待进程失败!"<<std::endl;
}
return 0;
}
4.execle和execve函数:
有e的是要进行自己进行组装环境变量的。
带e的,需要⾃⼰组装环境变量
execle("ps", "ps", "-ef", NULL, envp);
带e的,需要自己组装函数变量
execve("/bin/ps",argv,envp);
execvpe函数:
函数原型:
int execvpe(const char* file,char* const argv[],char* const env[]);
函数解释:
1.env是我们传递的全新的环境变量。对于env我们可以传递父进程的环境变量,也可以在父进程的环境变量上新增。
2.刚刚开始的bash进程就要传递自己写的环境变量。自己写的环境变量,自己定义,自己传递。
3.如何新增环境变量:
getenv:获取环境变量。
#include <stdlib.h>
char *getenv(const char *name);
putenv:新增环境变量。
#include <stdlib.h>
int putenv(char *string);
总结:
实际上,只有execve才是真正的系统调用,其他的函数都是调用execve。所以execve在man的手册2,其他函数在手册3。