进程程序替换
创始人
2024-04-27 09:42:14
0

文章目录

  • 进程程序替换是什么
    • 概念
    • 原理
  • 为什么要进行程序替换
  • 如何进行程序替换
  • 使用接口
    • execl
  • 引入进程创建
    • execv
    • execlp
    • execvp
    • execle


进程程序替换是什么

概念

通过之前的学习,我们知道子进程执行的是父进程的代码片段。
如果我们想让创建出来的子进程,执行的是全新的程序呢?
这里我们就需要用到进程程序替换。

原理

1.将磁盘中的程序,加载入内存结构
2.重新建立页表映射,谁执行程序替换,就重新建立谁的映射(子进程)
效果:让我们的父进程和子进程彻底分离,并让子进程执行一个新的程序。

在这里插入图片描述

那么问题来了!!!

这个过程有没有创建新的进程呢?

答:我们肯定没有创建新的进程,只不过让子进程执行了新的程序


为什么要进行程序替换

我们一般在服务器设计(linux编程)的时候,往往需要子进程干两件种类的事情

  • 1.让子进程执行父进程的代码片段(服务器代码)
  • 2.让子进程执行磁盘中的一个全新的程序(shell,想让客户端执行对应的程序,通过我们的进程,执行其他人写的进程的代码等等)
    例如我们用C语言的进程去掉java/python/C++等等的程序。

如何进行程序替换

由OS完成,所以我们要调用系统接口。

首先带大家来看看系统接口有什么!

在这里插入图片描述
我们如果要执行一个全新的程序,我们需要做几件事情呢?

  • 程序本质就是一个磁盘上的文件,所以我们需要先找到这个程序在哪里
  • 程序可能携带选项进行执行(也可以不携带),然后告诉OS,我要怎么执行这个程序?(要不要带选项)

使用接口

execl

在这里插入图片描述

其中参数列表中:“…” 叫做可变参数,说白了就是可以按照用户的意愿传入参数的大小个数,如果还不理解,大家肯定都用过C语言中的printf函数吧,printf有没有规定你只能打印几个参数呢?没有的,这是根据用户自己来定义的!这就是可变参数

在这里插入图片描述

执行完以上的代码,我们发现一个问题!!!

最后一句代码为什么没有被打印出来呢???
因为进程一旦替换成功,是将当前进程的代码和数据全部替换了!!!

后面的printf是代码吗??有没有被替换呢??当然,已经早就被替换了!!该代码不存在了!!

所以这个程序替换函数,用不用判断返回值?为什么?
答:不用判断返回值,因为只要成功了,就不会有返回值。而失败的时候,必然会继续向后执行!!最多通过返回值得到什么原因导致的替换失败!

引入进程创建

#include
#include
#include
#include
#include
#includeint main()
{printf("我是一个进程: %d\n",getpid());pid_t id=fork();if(id==0){printf("我是子进程,我的pid是:%d\n",getpid());execl("/usr/bin/ls","ls","-l","-a",NULL);exit(1);}int status=0;pid_t ret=waitpid(id,&status,0);if(ret==id){sleep(2);                 printf("父进程等待成功!\n");}return 0;
}

在这里插入图片描述

子进程进行程序替换的时候会不会影响父进程呢?
答:不会,因为进程具有独立性。

为什么?如何做到的?
因为数据层面发生了写时拷贝!当程序替换的时候,我们可以理解成为,代码和数据都发生了写时拷贝,完成了父子的分离。

execv

他的第二个参数是一个指针数组,他和execl的区别就是把选项作为参数放入指针数组,然后进行传参!

int main()7 {8     printf("我是一个进程,我的pid是:%d\n",getpid());9     pid_t id=fork(); 10     if(id==0)11     {12         //child13         //我们想让子进程执行新的程序,以前是执行父进程的代码片段14         printf("我是子进程,我的pid是:%d\n",getpid());15       char *const argv_[]={16         (char*)"ls",17         (char*)"-a",18         (char*)"-l",19          NULL20          };21       execv("/usr/bin/ls",argv_);                                                                                                            22         exit(1);23     }24     //一定是父进程25     int status=0;26     int ret=waitpid(id,&status,0);27     if(ret==id)28     {29         sleep(2);30         printf("父进程等待成功!\n");31     }32 33     return 0;34 }

在这里插入图片描述
区分execl和execv
在这里插入图片描述

execlp

在这里插入图片描述

相比于execl这个接口的第一个参数变化。
我们执行指令的时候,默认的搜索路径,在哪里搜索呢?
环境变量PATH!

p代表PATH

所以命名中带p的,可以不带路径,只要说出你要执行哪一个程序即可!

#include
#include
#include
#includeint main()
{printf("我是一个进程,我的pid是:%d\n",getpid());pid_t id=fork(); if(id==0){//child//我们想让子进程执行新的程序,以前是执行父进程的代码片段printf("我是子进程,我的pid是:%d\n",getpid());char *const argv_[]={(char*)"ls",(char*)"-a",(char*)"-l",NULL};execlp("ls","ls","-a","-l",NULL);//这里出现了两个ls,含义一样吗?不一样!exit(1);}//一定是父进程int status=0;int ret=waitpid(id,&status,0);if(ret==id){sleep(2);printf("父进程等待成功!\n");}return 0;
}

在这里插入图片描述

execvp

在这里插入图片描述

#include 
#include 
#include 
#include int main()
{printf("我是一个进程,我的pid是:%d\n", getpid());pid_t id = fork();if (id == 0){// child// 我们想让子进程执行新的程序,以前是执行父进程的代码片段printf("execvp 我是子进程,我的pid是:%d\n", getpid());char *const argv_[] = {(char *)"ls",(char *)"-a",(char *)"-l",NULL};execvp("ls", argv_);exit(1);}// 一定是父进程int status = 0;int ret = waitpid(id, &status, 0);if (ret == id){sleep(2);printf("父进程等待成功!\n");}return 0;
}

在这里插入图片描述

execle

在这里插入图片描述
这里的前两个接口都非常熟悉了,这里最后一个接口叫做环境变量。那么为什么要有这个接口呢?

说到环境变量之前我们先来看一下这个问题,我们刚刚提到过,进程替换可以让我们执行其他语言写的程序,那么我们怎么来执行呢?(我们使用execl 函数来调用)

我们现在的目标是想用我们写的myexec.c把mycmd.cpp调用起来,那么怎么来用呢?
myexec.c

#include 
#include 
#include 
#include int main()
{printf("我是一个进程,我的pid是:%d\n", getpid());pid_t id = fork();if (id == 0){// child// 我们想让子进程执行新的程序,以前是执行父进程的代码片段printf("execl 运行mycmd 我是子进程,我的pid是:%d\n", getpid());/*char *const argv_[] = {(char *)"ls",(char *)"-a",(char *)"-l",NULL};*/execl("/home/jys/code.c/mycmd", "mycmd",NULL);exit(1);}// 一定是父进程int status = 0;int ret = waitpid(id, &status, 0);if (ret == id){sleep(2);printf("父进程等待成功!\n");}return 0;
}

mycmd.cc

#include 
using namespace std;
int main()
{cout << "你调用了我,很好,你成功引起了我的注意" << endl;cout << "你调用了我,很好,你成功引起了我的注意" << endl;cout << "你调用了我,很好,你成功引起了我的注意" << endl;cout << "你调用了我,很好,你成功引起了我的注意" << endl;cout << "你调用了我,很好,你成功引起了我的注意" << endl;cout << "你调用了我,很好,你成功引起了我的注意" << endl;return 0;
}

在这里插入图片描述
我们当前使用的是绝对路径来吊用我的mycmd程序!
当然我们也可以使用相对路径来调用。

所以我们使用ece系列的系统级函数可以把任何语言耦合在一起!

谈完这个话题我们再来谈谈环境变量,execle这个函数多了一个e,这个e就是环境变量,如果你想给这个函数传入环境变量,我们就可以传入环境变量。
在这里插入图片描述
myexec.c

#include 
#include 
#include 
#include int main()
{extern char** __environ;printf("我是一个进程,我的pid是:%d\n", getpid());pid_t id = fork();if (id == 0){// child// 我们想让子进程执行新的程序,以前是执行父进程的代码片段printf("execle 运行mycmd 我是子进程,我的pid是:%d\n", getpid());execle("/home/jys/code.c/mycmd", "mycmd",NULL,__environ);exit(1);}// 一定是父进程int status = 0;int ret = waitpid(id, &status, 0);if (ret == id){sleep(2);printf("父进程等待成功!\n");}return 0;
}

mycmd.cc

#include 
#include
using namespace std;
int main()
{cout<

在这里插入图片描述
这个是父进程用extern继承了系统的环境变量,子进程继承了父进程的环境变量


#include 
#include 
#include 
#include int main()
{// extern char** __environ;printf("我是一个进程,我的pid是:%d\n", getpid());pid_t id = fork();if (id == 0){// child// 我们想让子进程执行新的程序,以前是执行父进程的代码片段printf("execle 运行mycmd 我是子进程,我的pid是:%d\n", getpid());/*char *const argv_[] = {(char *)"ls",(char *)"-a",(char *)"-l",NULL};*/char* const env_[]={(char*)"MYPATH=迪丽热巴我老婆\n",NULL};execle("./mycmd", "mycmd",NULL,env_);exit(1);}// 一定是父进程int status = 0;int ret = waitpid(id, &status, 0);if (ret == id){sleep(2);printf("父进程等待成功!\n");}return 0;
}

在这里插入图片描述

#include 
#include
using namespace std;
int main()
{cout<

在这里插入图片描述

这里我们发现我们导入的环境变量出现了!

我们很好奇为什么呢?依照上面两个实验我们可以得出什么结论呢?

我们可以得出execle添加环境变量给目标程序的时候是覆盖式传入的!!

我们自己传入系统的环境变量给我们程序替换的程序


#include 
#include 
#include 
#include int main()
{extern char** __environ;printf("我是一个进程,我的pid是:%d\n", getpid());pid_t id = fork();if (id == 0){// child// 我们想让子进程执行新的程序,以前是执行父进程的代码片段printf("execle 运行mycmd 我是子进程,我的pid是:%d\n", getpid());/*char *const argv_[] = {(char *)"ls",(char *)"-a",(char *)"-l",NULL};*///char* const env_[]={(char*)"MYPATH=迪丽热巴我老婆\n",NULL};execle("./mycmd", "mycmd",NULL,__environ);exit(1);}// 一定是父进程int status = 0;int ret = waitpid(id, &status, 0);if (ret == id){sleep(2);printf("父进程等待成功!\n");}return 0;
}

在这里插入图片描述

在这里插入图片描述

相关内容

热门资讯

芙蓉律师事务所律师在全省律师行... 金秋送爽,捷报频传。在近日举办的全省律师行业迎国庆运动会中,芙蓉律师事务所运动健儿屡创佳绩,凭借出色...
OpenAI与英伟达宣布合作伙... 每经AI快讯,当地时间9月22日,OpenAI与英伟达宣布建立合作伙伴关系的意向书。英伟达有意将逐步...
广州一医院发生伤医事件,医生“... 中国新闻周刊 红星新闻 9月22日,广州中医药大学第一附属医院被曝发生伤医事件。《中国新闻周刊》记者...
云南全省提振消费政策持续显效 近日,省统计局发布数据显示:8月份,全省实现社会消费品零售额1045.64亿元,同比增长3.3%。从...
治安处罚=终身污点?这项制度为... 治安处罚=终身污点?这项制度为轻微过错者“松绑” 在日常生活当中,很多人都遇到过或见到过因为一些小...
欧盟数字金融法规有望数周内定案... IT之家 9 月 23 日消息,科技媒体 9to5Mac 昨日(9 月 22 日)发布博文,报道称欧...
商业秘密律师:被告技术与原告技... 最高法院:被告技术与原告技术不同,是否影响侵权认定? 在被告很可能接触原告技术秘密且没有合法来源的情...
加码助力海归创业,奉贤在海归小... 昨天,“贤聚四海智创未来”上海首届海归小镇留学生嘉年华在奉贤开幕。活动现场,奉贤区发布《关于支持上海...
原创 火... 北京时间9月23日消息,来自名记Shams的报道称,消息灵通人士透露,火箭队后卫乔丹-范弗里特遭遇前...
聚焦·全国“质量月”丨“纸面制... 韩国富 “这道焊缝再量一遍,数据必须百分百准确!”在中油电能热电一公司1号机组B级检修现场,热机检修...