中小企业网站建设案例,阿里云域名备案网站建设方案书,外贸订单信息,html样式模板文章目录 一、进程程序替换#xff08;一#xff09;概念#xff08;二#xff09;为什么程序替换#xff08;三#xff09;程序替换的原理#xff08;四#xff09;如何进行程序替换1. execl2. 引入进程创建——子进程执行程序替换#xff0c;会不会影响父进程呢? 一概念二为什么程序替换三程序替换的原理四如何进行程序替换1. execl2. 引入进程创建——子进程执行程序替换会不会影响父进程呢? 五大量的测试各种不同的接口1.命名理解 带v和带l的2.记忆技巧3.带e和带p 六具体接口说明1.execv2.execlp3.execvp4.execle 二、模拟实现shell三、内建命令——以chdir为例 一、进程程序替换
一概念 子进程执行的是父进程的代码片段如果我们想让创建出来的子进程执行全新的程序呢? 需要用到进程的程序替换
二为什么程序替换
我们一般在服务器设计(linux编程)的时候往往需要子进程干两件种类事情
让子进程执行父进程的代码片段(服务器代码)让子进程执行磁盘中一个全新的程序(shell想让客户端执行对应的程序通过我们的进程执行其他人写的进程代码等等)c/c -c/c/Python/Shell/Php/Java…
三程序替换的原理
将磁盘中的程序加载入内存结构重新建立页表映射谁执行程序替换就重新建立谁的映射(子进程)
效果让我们的父进程和子进程彻底分离并让子进程执行一个全新的程序! 这个过程有没有创建新的进程呢? 没有子进程的PCB等结构并未改变只是改变的页表映射关系。
程序替换成功后运行完新程序则程序直接退出程序替换成功后原进程没有退出使用原进程运行新程序 我们只能调用接口为什么呢 因为这个过程实际上是把数据从一个硬件搬到另一个硬件的操作这个操作只能由OS操作系统完成
四如何进行程序替换
man execl 查看进行程序替换的函数 我们如果要执行一个全新的程序我们需要做几件事情呢
1.程序本质就是一个磁盘上的文件所以我们需要先找到这个程序在哪里 2.程序可能携带选项进行执行(也可以不携带)然后告诉OS我要怎么执行这个程序(要不要带选项)
命令行怎么写(ls -l -a) 这个参数就怎么填ls“-l”“-a”,最后必须是NULL标识参数传递完毕[如何执行程序的] #include unistd.hextern char **environ;int execl(const char *path, const char *arg, ...);int execlp(const char *file, const char *arg, ...);int execle(const char *path, const char *arg,..., char * const envp[]);int execv(const char *path, char *const argv[]);int execvp(const char *file, char *const argv[]);int execvpe(const char *file, char *const argv[],char *const envp[]);1. execl
makefile
myexec:myexec.cg -o $ $^ -stdc11
.PHONY:clean
clean:rm -f myexecmyexec.c
#includestdio.h
#includeunistd.h
#includestdlib.h
#includeassert.h
#includesys/types.h
#includesys/wait.hint main(int argc,char *argv[]) {printf(process is running...\n);pid_t id fork();assert(id ! -1);if (id 0) {sleep(1);printf(我是一个进程我的pid是%d\n,getpid());// 执行ls -l -a 命令//execl(/usr/bin/ls,ls,-l,-a,NULL); // 这里有两个ls, 重复吗不重复一个是告诉系统我要执行谁一个是告诉系统我想怎么执行// 执行top命令execl(/usr/bin/top,top,NULL); printf(我执行完毕了我的pid是%d\n,getpid()); // 执行完以上的代码我们发现一个问题// 最后一句代码为什么没有被打印出来呢}return 0;
}因为进程一旦替换成功是将当前进程的代码和数据全部替换了
后面的printf是代码吗有没有被替换呢当然已经早就被替换了该代码不存在了 所以这个程序替换函数用不用判断返回值为什么 答:不用判断返回值因为只要成功了就不会有返回值execl一旦替换成功是将当前进程的所有代码和数据全部替换了execl就直接执行ls命令的代码去了。。而失败的时候必然会继续向后执行最多通过返回值得到什么原因导致的替换失败
2. 引入进程创建——子进程执行程序替换会不会影响父进程呢?
子进程执行程序替换会不会影响父进程呢? ?
不会因为进程具有独立性。 为什么如何做到的? ?数据层面发生写时拷贝!当程序替换的时候我们可以理解成为代码和数据都发生了写时拷贝完成父子的分离!
五大量的测试各种不同的接口
1.命名理解 带v和带l的
这些函数原型看起来很容易混,但只要掌握了规律就很好记。l(list) : 表示参数采用列表v(vector) : 参数用数组p(path) : 有p自动搜索环境变量PATHe(env) : 表示自己维护环境变量2.记忆技巧
execl结尾 l 为list列表传参——可变参数包一个一个传。execv结尾 v 为vector数组传参——传的是指针数组。3.带e和带p
带e的都是可以传环境变量的execleexecvpe但是会覆盖系统原有的环境变量把自己传的环境变量交给进程 不带e是默认继承系统的环境变量带p的都是可以自带路径的直接传命令名称即可execlpexecvpexecvpe
六具体接口说明
1.execv
int execv(const char *path, char *const argv[]); path 依然是程序的路径参数 argv[] 是存着要实现指令的指针数组
char *const argv_[] {ls,-a,-l,--colorauto,NULL
};2.execlp
int execlp(const char *file, const char *arg, ...); 带p的就传程序名即可file要执行的程序。执行指令的时候默认的搜索路径在哪里搜索呢?在环境变量PATH
命名带p的可以不带路径只说出你要执行哪一个程序即可!execlp(lsls, -a, -1 NULL)#includestdio.h
#includeunistd.h
#includestdlib.h
#includeassert.h
#includesys/types.h
#includesys/wait.hint main(int argc,char *argv[]) {printf(process is running...\n);pid_t id fork();assert(id ! -1);if (id 0) {sleep(1);printf(我是一个进程我的pid是%d\n,getpid());//execl(/usr/bin/ls,ls,-l,-a,NULL); // 这里有两个ls, 重复吗不重复一个是告诉系统我要执行谁一个是告诉系统我想怎么执行// 执行top命令char *const argv_[]{(char*)ls,(char*)-a,(char*)-l,NULL};//execl(/usr/bin/top,top,NULL); execlp(ls,ls,-a,-l,NULL);//这里出现了两个ls含义一样吗不一样exit(1); //execvp(ls, argv_);printf(我执行完毕了我的pid是%d\n,getpid()); // 执行完以上的代码我们发现一个问题// 最后一句代码为什么没有被打印出来呢}int status 0;int ret waitpid(id,status,0);if(ret id){sleep(2);printf(父进程等待成功\n);}return 0;
}3.execvp int execvp(const char *file, char *const argv[]);#includestdio.h
#includeunistd.h
#includestdlib.h
#includeassert.h
#includesys/types.h
#includesys/wait.hint main(int argc,char *argv[]) {printf(process is running...\n);pid_t id fork();assert(id ! -1);if (id 0) {sleep(1);printf(我是一个进程我的pid是%d\n,getpid());//execl(/usr/bin/ls,ls,-l,-a,NULL); // 这里有两个ls, 重复吗不重复一个是告诉系统我要执行谁一个是告诉系统我想怎么执行// 执行top命令char *const argv_[]{(char*)ls,(char*)-a,(char*)-l,NULL};//execl(/usr/bin/top,top,NULL); //execlp(ls,ls,-a,-l,NULL);//这里出现了两个ls含义一样吗不一样exit(1); execvp(ls, argv_);printf(我执行完毕了我的pid是%d\n,getpid()); // 执行完以上的代码我们发现一个问题// 最后一句代码为什么没有被打印出来呢}// 父进程int status 0;int ret waitpid(id,status,0);if(ret id){sleep(2);printf(父进程等待成功\n);}return 0;
}4.execle
int execle(const char *path, const char *arg,..., char * const envp[]);这里的前几个接口都非常熟悉了这里最后一个接口叫做环境变量。那么为什么要有这个接口呢
说到环境变量之前我们先来看一下这个问题我们刚刚提到过进程替换可以让我们执行其他语言写的程序那么我们怎么来执行呢我们使用execl 函数来调用
我们现在的目标是想用我们写的myexec.c把mycmd.cpp调用起来那么怎么来用呢 myexec.c
我们当前使用的是绝对路径来调用我的mycmd程序
当然我们也可以使用相对路径来调用。
相对路径调用—— makefile
.PHONY:all
all: mybin myexec
mybin:mybin.cg -o $ $^ -stdc11
myexec:myexec.cg -o $ $^ -stdc11
.PHONY:clean
clean:rm -f myexec mybin#includestdio.h
#includeunistd.h
#includesys/wait.h
#includestdlib.hint main()
{printf(我是一个进程我的pid是%d\n,getpid());pid_t idfork(); if(id0){//childprintf(我是子进程我的pid是%d\n,getpid());execl(./mycmd,mycmd,NULL);exit(1);}//一定是父进程int status0;int retwaitpid(id,status,0);if(retid){sleep(2);printf(父进程等待成功\n);}return 0;
} 为什么会有这么多接口?——因为要适配应用场景。
execve为什么是单独的?——实际上只有 execve是系统调用其他都是对系统接口的封装最后都要调用到execve!
二、模拟实现shell
三、内建命令——以chdir为例