初识Linux · 进程替换

目录

前言:

[1 直接看代码和现象](#1 直接看代码和现象)

[2 解释原理](#2 解释原理)

[3 将代码改成多进程版本](#3 将代码改成多进程版本)

[4 认识所有函数并使用](#4 认识所有函数并使用)


前言:

由前面的章节学习,我们已经了解了进程状态,进程终止以及进程等待,今天,我们学习进程替换。进程替换我们从如下几个点开始介绍,第一,直接看现象,第二,解释原理,第三,将代码改成多线程版本,第四,使用所有的替换函数,认识参数的含义。

废话不多说,直接进入主题。


1 直接看代码和现象

我们使用一段代码进入到进程替换:

cpp 复制代码
int main()
{
	printf("test begin...\n");	
	execl("/usr/bin/ls","-l",NULL);
	printf("test end...\n");	
	return 0;
}

根据现象,我们可以看到,第二个printf是没有被执行的,但是第一个被执行了,而我们使用到的函数,叫做进程替换函数,它一共有6种,本质上我们理解了其中的2 - 3个,我们就会使用全部的了。我们不妨使用man手册查看一下:

输入:

man exec

从文档里面我们可以看到进程替换的函数版本有这么多个,每个函数都有返回值,但是呢我们不必在意返回值,因为通过现象,我们看到了执行进程替换函数之后的代码都失效了,所以返回值即使接受了,也没有用处。

关心的情况只有一种,就是进程替换失败,但是这种情况十分的少见,我们就自然而然的给忽略了。


2 解释原理

首先我们要清楚一个问题,进程替换的全名不是进程替换,替换的不是进程,是程序,所以在进程程序替换的这个过程,本质上是没有创建新的进程的。

第一个点:进程程序替换中是没有创建新进程的,无非是程序替换了PCB里面原来的数据。这里我们不妨设想一个点,如果PCB里面是自己替换自己的多没意思,如果.cpp文件里的PCB可以被Java替换,shell脚本替换,岂不美哉?

第二个点,exec函数的作用是什么?

exec函数本质是一个加载函数,因为有了exec函数,在Linux中就可以将程序加载进去,因为进程程序替换的本质就是将不同的程序加载到内存里面,加载靠的就是exec*函数。


3 将代码改成多进程版本

将代码改成多线程版本,我们要做的事就是,父进程创建子进程,创建了之后,子进程执行被替换的程序,父进程只需要等待多个子进程就可以了。

此时,子进程的作用就有了两个,一个是执行父进程的代码部分,一个是让子进程执行一个全新的程序。

cpp 复制代码
int main()
{
    printf("testexec ... begin!\n");
    pid_t id = fork();
    if (id == 0)
    {
        printf("child pid: %d\n", getpid());
        //child
        execl("/usr/bin/ls", "ls", "-l", NULL);
        exit(1);
    }
    int status = 0;
    pid_t rid = waitpid(id, &status, 0);
    if (rid > 0)
    {
        printf("father wait success, child exit code: %d\n", WEXITSTATUS(status));
    }
    printf("testexec ... end!\n");
    return 0;
}

该程序创建了一个子进程,子进程实现execl,如果执行失败,也就是替换失败,就走exit,程序直接退出,退出码为1,此时父进程只需要等待即可:

以上是现象,今天的重点都不是前三个,直接进入第四个。


4 认识所有函数并使用

所有的函数一共有execl execlp execle execv execvp execvpe,不难发现,拿命令行参数进行举例的话,选项一共有l p e v。

由参数,我们可以看到有pathname 和file,我们第一个使用的pathname即路径名,我们要从哪里执行程序,得通过该路径告诉它,file同理,就是文件名,那么对于execl,代表的就是列表,也就是在命令行中我们如何执行,在该函数里面就怎么书写即可。

拿这个举例:

execl("/usr/bin/ls","ls"."-l",NULL);

因为有l,所以我们要将平常执行ls命令的时候,如何执行的给列出来,这个参数不是固定,所以我们可以执行很多,ls -l -a -n都是可以的,但是注意点是最后的参数一定要是NULL,代表结束。

第二个函数:

execv,这里面的v代表的是vector,C++中的顺序表,所以我们看execv的参数是\[\],也就是我们应该这样干:

cpp 复制代码
int main()
{
    char* const argv[] =
    {
        (char*)"ls",
        (char*)"-l",
        (char*)"-a",
        (char*)"--color",
        NULL
    };
    execv("/usr/bin/ls", argv);

    return 0;
}

但是注意点是,最后结尾的仍然要是NULL,这里的强转char*不是很必要,看自己的版本是否会进行报错吧。

对于execvp:

p代表的是PATH,也就是环境变量,用户可以不用传对应的路径,但是要传对应的文件,就像:

cpp 复制代码
int main()
{
    char* const argv[] =
    {
        (char*)"ls",
        (char*)"-l",
        (char*)"-a",
        (char*)"--color",
        NULL
    };
    //execv("/usr/bin/ls", argv);
    execvp("ls",argv);
    return 0;
}

那么现在关于execlp就应该不用介绍了吧?l,list出来命令行怎么写的即可,p我们传对应的文件名即可。

现在还没介绍的就只有e了,e多好理解,environment,环境变量嘛不就是,当然了,因为父进程本身就有环境变量,子进程哪里用得着担心我没有环境变量啥的,根本不担心:

使用这里就不介绍了,同理即可。

本文是非常粗略的介绍了一下进程程序替换,很多细节没有介绍到,博主会在后面全部重新翻新的!!


感谢阅读!

相关推荐
大树886 小时前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠7 小时前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质7 小时前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
bush47 小时前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5207 小时前
Linux 11 动态监控指令top
linux
小宇宙Zz7 小时前
Maven依赖冲突
java·服务器·maven
Inhand陈工8 小时前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智8 小时前
ARP代理--工作原理
运维·网络·arp·arp代理
不会C语言的男孩9 小时前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言
shushangyun_9 小时前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化