西部数码网站管理助手 伪静态,湖北高端网站建设价格,快速搭建网站demo,扬州市住房建设局网站上次讲了#xff1a;Linux#xff1a;进程地址空间、进程控制#xff08;一.进程创建、进程终止、进程等待#xff09; 文章目录 1.进程程序替换1.1概念1.2原理1.3使用一个exec 系列函数execl#xff08;#xff09;函数结论与细节 2.多进程时的程序替换3.其他几个exec系…上次讲了Linux进程地址空间、进程控制一.进程创建、进程终止、进程等待 文章目录 1.进程程序替换1.1概念1.2原理1.3使用一个exec 系列函数execl函数结论与细节 2.多进程时的程序替换3.其他几个exec系列函数也可以调用其他语言的程序想要生成两个可执行文件的makefile 1.进程程序替换 之前我们进行的程序演示里都只能运行自己的代码。那我们怎么样才能执行其他程序的代码呢例如在程序里使用ls之类的指令就可以使用进程程序替换一开始我们先只看单进程的情况。后面在引入多进程的情况 1.1概念
进程程序替换是指在运行过程中将一个进程的地址空间中的代码、数据和堆栈等内容完全替换为另一个程序的代码、数据和堆栈的过程。这个过程通常是由操作系统提供的 exec 系列函数来实现的 地址空间替换进程的地址空间是指进程可以访问的内存范围。通过地址空间替换进程可以在运行时动态地加载并执行不同的程序从而实现灵活的程序执行和管理。 exec 函数族exec 函数族是一组系统调用用于执行程序替换操作。这些函数包括 execl, execv, execle, execve 等它们允许以不同的方式传递参数给新程序并执行地址空间替换。 我们要改变内存那肯定是要调用系统调用接口的这些函数会封装相应的接口 程序入口点新程序的入口点是程序中的起始执行位置通常是 main 函数或其他指定的入口函数。替换完成后控制权将转移到程序入口点开始执行新程序的代码。
1.2原理
当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换替换完成后控制权将转移到新程序的入口点开始执行新程序的代码。 1.3使用一个exec 系列函数
execl函数
execl函数是Linux系统中用于执行新程序的函数之一它属于exec函数族的一部分。这个函数的作用是在当前进程的上下文中启动一个新的程序并替换当前进程的映像为新的程序映像。调用execl函数后当前进程将停止执行并由新的程序开始执行。
#includeunistd.h
int execl(const char *path, const char *arg0, ... /* (char *) NULL */);参数说明
path要执行的程序的路径。arg0新程序的参数列表的开始通常这会是新程序的名称尽管这不是强制的但它通常用于错误消息和程序内部。...一个可变参数列表参数的数量不固定新程序的参数列表必须以NULL结尾。 execl函数会根据提供的路径path找到并执行相应的程序同时将arg0及其后面的参数作为新程序的命令行参数传递。注意参数列表必须以NULL结尾这是告诉execl参数列表结束的标志。 #include stdio.h
#include unistd.h
#include stdlib.h
#include sys/types.h
#include sys/wait.hint main()
{printf(Im a process, pid: %d\n, getpid());printf(execl begin...\n);int aexecl(/usr/bin/ls, ls, -a, -l, NULL);printf(execl end...\n);return 0;
}如果execl函数调用成功那么它实际上不会返回因为当前进程的映像已经被新程序替换。如果调用失败它会返回-1并设置全局变量errno以指示错误原因。常见的错误原因可能包括文件未找到、权限不足等。
execl函数和其他exec函数一样不会创建新的进程。它们只是在当前进程的上下文中启动另一个程序。
因此调用execl前后进程的IDPID不会改变。同时由于execl会替换整个进程映像所以在调用execl之前通常需要确保当前进程的所有打开的文件描述符、内存分配等都被适当地处理或释放因为这些资源不会被新程序继承。
结论与细节 程序替换一旦成功exec后面的代码不在执行。因为被替换掉了这也是什么代码没有输出execl end的原因了 exec函数调用成功那么它实际上不会有返回值调用失败它会返回-1 exec函数不会创建新的进程。它们只是在当前进程的上下文中启动另一个程序 创建一个进程。我们是先创建PCB、地址空间、页表等再先把程序加载到内存 先加载的话页表都没办法映射的 程序替换的本质就是加载 可以看成一个加载器有替换就是替换没有就是程序加载 程序替换的本质是程序加载因为在执行 exec 函数时操作系统会加载新程序的可执行文件并将其代码、数据和堆栈等部分加载到进程的地址空间中。这个过程涉及将新程序的内容从磁盘加载到内存中为进程提供执行所需的资源。因此虽然我们常说是“程序替换”但实际上更准确地说是将新程序加载到内存中替换掉原有的程序以实现进程的功能切换和更新。 程序运行要加载到内存为什么冯诺依曼体系规定如何加载的呢就是程序替换程序替换是操作系统的接口所谓的把磁盘里的数据加载到内存就是把磁盘设备的数据拷贝到内存里。把数据从一个硬件搬到另一个硬件只有操作系统能做
2.多进程时的程序替换
我们可以创建一个子进程由子进程来进行程序替换父进程来等待结果就可以。为什么 父进程能得到子进程的执行结果
我们知道父进程与子进程映射到同一块代码那么子进程进行程序替换后不是会覆盖吗替换为什么不影响父进程 进程具有独立性在进行程序替换时要进行写时拷贝 写时拷贝的本质就是开辟新的空间 shell是如何运行起来一个指令的 首先创建子进程shell会waitpid等待进程结果子进程会继承shell的代码但是不影响。子进程进行程序替换替换为我们输入的指令 int main()
{pid_t id fork();if (id 0){printf(Im a process, pid: %d\n, getpid());printf(execl begin...\n);execl(/usr/bin/ls, ls, -a, -l, NULL);printf(execl end...\n);exit(1);}pid_t rid waitpid(id, NULL, 0);if (rid 0){printf(wait successfully\n);}return 0;
}3.其他几个exec系列函数 execl该函数允许通过提供可变数量的参数来执行指定的可执行文件。它的原型如下 int execl(const char *path, const char *arg0, ... /*, (char *)0 */);path 是要执行的可执行文件的路径arg0 是第一个参数后续参数都是传递给可执行文件的命令行参数以 NULL 结尾。 execlp该函数与 execl 类似但是它会在系统的环境变量 PATH 指定的目录中查找可执行文件。它的原型如下 int execlp(const char *file, const char *arg0, ... /*, (char *)0 */);file 是要执行的可执行文件的文件名arg0 是第一个参数后续参数都是传递给可执行文件的命令行参数以 NULL 结尾。 相比于execl函数execlp函数的第一个参数能直接写文件名系统会PATH环境变量里去查找 多的字母pPATH环境变量 int main()
{pid_t id fork();if (id 0){printf(Im a process, pid: %d\n, getpid());printf(execl begin...\n);execl(ls, ls, -a, -l, NULL);printf(execl end...\n);exit(1);}pid_t rid waitpid(id, NULL, 0);if (rid 0){printf(wait successfully\n);}return 0;
}execv类似于 execl但是允许传递一个参数数组给被执行的程序。它的原型如下 int execv(const char *path, char *const argv[]);path 是要执行的可执行文件的路径argv 是一个以 NULL 结尾的参数数组其中每个元素都是一个字符串表示命令行参数。 相比于exec多个字母v代表vector int main()
{pid_t id fork();if (id 0){printf(Im a process, pid: %d\n, getpid());printf(execl begin...\n);char* argv[] { ls,-a,-l,NULL};execv(/usr/bin/ls,argv);printf(execl end...\n);exit(1);}pid_t rid waitpid(id, NULL, 0);if (rid 0){printf(wait successfully\n);}return 0;
}execvp类似于 execv但是它会在系统的环境变量 PATH 指定的目录中查找可执行文件。它的原型如下
int execvp(const char *file, char *const argv[]);file 是要执行的可执行文件的文件名argv 是一个以 NULL 结尾的参数数组其中每个元素都是一个字符串表示命令行参数。 既有字母p 又有v结合上面那两种就行 execle函数与 execl 函数类似但允许在启动新程序时传递额外的环境变量。它的原型如下 int execle(const char *path, const char *arg, ..., char *const envp[]);path 是要执行的可执行文件的路径arg 是要传递给新程序的命令行参数后面的参数是额外的环境变量以 NULL 结尾。 进程程序替换不会替换环境变量的 想要子进程继承全部的环境变量不用管直接就能拿到 单纯新增环境变量在父进程里使用putenv()函数会影响子进程 putenv 是 C 语言中的一个库函数它定义在 stdlib.h 头文件中。这个函数用于将字符串添加到环境变量中或者修改已经存在的环境变量的值。 int putenv(const char *string);使用全新的环境变量就使用execle()函数那么替换后的代码切换后的环境变量就只是我们传入的表里的内容 也可以调用其他语言的程序
code.c里
int main()
{char* const env[] {(char*)first,(char*)second,NULL };pid_t id fork();if (id 0){printf(Im a process, pid: %d\n, getpid());printf(execl begin...\n);execle(./mytest, mytest, NULL, env)printf(execl end...\n);exit(1);}pid_t rid waitpid(id, NULL, 0);if (rid 0){printf(wait successfully\n);}return 0;
}test.cpp里
#include iostream
#include unistd.husing namespace std;int main()
{for (int i 0; environ[i]; i){printf(env[%d]: %s\n, i, environ[i]);}cout This is C endl;return 0;
}当然我们也能传系统环境变量但是没必要这样的话直接默认就行
execle(./mytest, mytest, NULL, environ)//传入这个全局变量想要生成两个可执行文件的makefile
.PHONY:all
all:mycode mytestmycode:code.cgcc -o $ $^
mytest:test.cppg -o $ $^ -stdc11
.PHONY:clean
clean:rm -f mycode mytest.PHONY声明一个或多个目标是伪目标phony targets通过声明伪目标你可以确保 make 总是执行相应的命令而不会因为同名的文件或目录的存在而跳过这些命令运行 make 命令时没有指定具体目标make 会首先查找 Makefile 中的第一个目标并尝试构建它。在这个过程中make 会检查该目标的所有依赖项并递归地处理这些依赖项直到所有必要的依赖项都被构建或确认为是最新的当 make 工具被调用以构建某个目标时它会检查该目标的所有依赖项并根据需要构建这些依赖项。然而对于 clean 这样的伪目标它并没有列出任何依赖项因此其他目标的构建状态不会影响 clean 的执行 今天就到这里啦感谢大家支持