【Linux】开始学习进程替换吧!

简介: 通过学习进程替换,我们可以体会到多语言混搭的快乐,可以从C语言直接蹦到python ,也可以从c++里运行java代码。是不是很厉害!这是通过调度多个进程的效果,联系我们之前学习的进程,进程控制等概念。我们可以想要运行其他代码可以通过创建子进程来实现,但是这样也肯定是同一种语言,如果想要运行其他语言,那是不是有种方法可以调度一个进程来当做子进程呢???我们开始今天的学习吧!

送给大家一句话:

人生中有些事,你不竭尽所能去做,你永远不知道你自己有多出色。—— 尾田荣一郎《海贼王》

开始学习进程替换吧

1 前言

通过学习进程替换,我们可以体会到多语言混搭的快乐,可以从C语言直接蹦到python ,也可以从c++里运行java代码。是不是很厉害!这是通过调度多个进程的效果,联系我们之前学习的进程,进程控制等概念。我们可以想要运行其他代码可以通过创建子进程来实现,但是这样也肯定是同一种语言,如果想要运行其他语言,那是不是有种方法可以调度一个进程来当做子进程呢???

我们开始今天的学习吧!

2 进程替换

2.1 替换函数

进程替换有六种以exec开头的函数,统称exec函数

#include <unistd.h>`
int execl(const char *path, const char *arg, ...);//...代表可变参数 类似printf
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 execve(const char *filename, char *const argv[],char* const envp[]);

我们来进行一下使用,来看看:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 
  4 int main()
  5 {
  6   printf("textexec ... begin!\n");
  7 
  8   execl("/usr/bin/ls","ls","-l","-a",NULL);                                                                                                                                   
  9                                                                                                
 10   printf("textexec ... end!\n");                                                               
 11   return 0;                                                                                    
 12 }  

可以看到执行了ls -l -a命令(最后的打印语句也没有进行),可是我执行的是我们的代码,怎么就运行了ls 这个程序呢?

原因就是:exec*系列函数可以执行起来新的程序,让进程通过exec函数把自己替换为一个全新的进程

2.2 替换原理

  • 用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支)
  • 子进程往往要调用一种exec函数以执行另一个程序。
  • 当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动 开始执行
  • 调用exec并不创建新进程,所以调用exec前后该进程的id并未改变
  • 没有创建新进程!!!

我们知道 进程 = 内核数据结构 + 代码和数据 ,替换就是用新进程的代码与数据替换之前的代码与数据,注意不改变pid哦!

站在被替换进程的角度:本质就是这个程序别加载到内存里了!!!exec* 就类似一个Linux 上的加载函数。


而且我们不用关心exec*函数的返回值,只要替换成功了,就不会向后运行(也就用不到它的返回值了),只要继续运行那一定就是替换失败了!!!

那如果不想替换掉我们的程序,还想要打开一个新程序呢??? 我们接着向下看

2.3 单进程改为多进程

方法很简单,我们通过fork函数创建一个子进程,让子进程来执行我们的新程序不就可以了吗!

1 #include<stdio.h>  
  2 #include<unistd.h>   
  3 #include<stdlib.h>
  4 #include<sys/types.h>
  5 #include<sys/wait.h>
  6 
  7 
  8 int main()
  9 {
 10   printf("textexec ... begin!\n");
 11   
 12   pid_t id = fork();
 13   if(id == 0)
 14   {
 15     //child
 16     execl("/usr/bin/ls","ls","-l","-a",NULL);
 17     exit(1);
 18   }
 19 
 20   int status = 0;
 21   pid_t rid = waitpid(-1,&status,0);
 22 
 23   if(rid > 0)
 24   {
 25     printf("father wait success,child exit code:%d \n",WEXITSTATUS(status));                                                                                                  
 26   }                                                                                                                     
 27   printf("testexec ... end!\n");                                                                                        
 28                                                                                                                         
 29   return 0;                                                                                                             
 30 }          

这个程序中:我们通过fork创建了一个子进程,然后在子进程中进行进程替换。这样应该就可以运行ls命令还不会影响原本程序。来看效果:

那么这样以后,创建子进程就变得非常有用了。我们可以通过子进程来完成对应任务:

  1. 让子进程完成父进程代码的一部分
  2. 让子进程执行一个全新的程序(会发生写时拷贝,建立全新的物理内存空间)

2.4 理解使用exec* 函数

这些函数原型看起来很容易混,但只要掌握了规律就很好记。

  • l(list) : 表示参数采用列表
  • v(vector) : 参数用数组
  • p(path) : 有p自动搜索环境变量PATH
  • e(env) : 表示自己维护环境变量

int execl (const char *path, const char *arg, …)

l 表示列表 list

两个参数分别代表:

  1. path (你想执行谁) : 我们执行的程序需要带路径
  2. arg(你想怎么执行) : 咳传多个 , 命令行里怎么运行就怎么写入!!! 举个例子:ls -a -l 所以我们传execl(“/usr/bin/ls” , “ls”,“-a”,“-l”) 。这样就像命令列表

通过这些函数也可以进行执行我们缩写的程序!!!


int execv (const char *path, char *const argv[])

v 表示数组 vector

这个方法就是把列表整合为一个数组,这样就直接传入一个数组(必须以NULL结尾!!!)就可以了:

char* const argv[] = 
{
  (char*)"ls",
  (char*)"-a",
  (char*)"-l",
  (char*)"--color",
  NULL
};
execv("/usr/bin/ls",argv);

是不是很想之前了解过的main函数参数!

int execvp(const char *file, char *const argv[])

带p含义是可以不传入文件路径,可以直接告诉exec*需要执行谁就可以了

本质就是:查找这个程序,系统会在系统环境变量PATH中的路径来寻找

char* const argv[] = 
{
  (char*)"ls",
  (char*)"-a",
  (char*)"-l",
  (char*)"--color",
  NULL
};
execvp("ls",argv);

这个 int execlp(const char *file, const char *arg, …) 同理!!!

execlp("ls" , "ls","-a","-l")

int execle(const char *path, const char *arg, …,char *const envp[])

这个就就加上了环境变量,让我们支持自主传入

int execve(const char *filename, char const argv[],char const envp[]) 同理 !!!

int execvpe(const char *filename, char const argv[],char const envp[])

这让我们可以传入环境变量给子进程!!!当然也会有一批来着"爷爷进程"bash的环境变量!

envp的含义是全体替换环境变量,所以会有以下情况:

  1. 用全新的给子进程
  2. 用老的环境变量给子进程 char** environ
  3. 老的环境变量稍微修改传给子进程 调用 putenv ()函数
char* const argv[] = 
{
  (char*)"ls",
  (char*)"-a",
  (char*)"-l",
  (char*)"--color",
  NULL
};
//用全新的给子进程
char* const envp[] = 
{
  (char*)"HAHA=111111",
  (char*)"HEHE=222222",
  NULL
};
//putenv("HAHA=111111")
//putenv("HEHE=222222");
//老的环境变量稍微修改传给子进程

execvpe("./myprocess",argv , encp);
//char** environ
// execvpe("./myprocess",argv , environ);

注意

根据上面的用法使用,我们可以总结一下:

函数名 参数格式 是否带路径 是否使用当前环境变量
execl 列表 不是
execlp 列表
execle 列表 不是 不是,需要自己组装环境变量
execv 数组 不是
execvp 数组
execve 数组 不是 不是,需要自己组装环境变量

而且只有 execle 是系统调用!!!他们的关系如下:

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

相关文章
|
21天前
|
资源调度 Linux 调度
Linux c/c++之进程基础
这篇文章主要介绍了Linux下C/C++进程的基本概念、组成、模式、运行和状态,以及如何使用系统调用创建和管理进程。
28 0
|
5天前
|
运维 Linux
Linux查找占用的端口,并杀死进程的简单方法
通过上述步骤和命令,您能够迅速识别并根据实际情况管理Linux系统中占用特定端口的进程。为了获得更全面的服务器管理技巧和解决方案,提供了丰富的资源和专业服务,是您提升运维技能的理想选择。
8 1
|
16天前
|
Linux 编译器 C语言
【Linux快速入门(一)】Linux与ROS学习之编译基础(gcc编译)
【Linux快速入门(一)】Linux与ROS学习之编译基础(gcc编译)
|
16天前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
【10月更文挑战第9天】本文将深入浅出地介绍Linux系统中的进程管理机制,包括进程的概念、状态、调度以及如何在Linux环境下进行进程控制。我们将通过直观的语言和生动的比喻,让读者轻松掌握这一核心概念。文章不仅适合初学者构建基础,也能帮助有经验的用户加深对进程管理的理解。
15 1
|
21天前
|
消息中间件 Linux API
Linux c/c++之IPC进程间通信
这篇文章详细介绍了Linux下C/C++进程间通信(IPC)的三种主要技术:共享内存、消息队列和信号量,包括它们的编程模型、API函数原型、优势与缺点,并通过示例代码展示了它们的创建、使用和管理方法。
20 0
Linux c/c++之IPC进程间通信
|
21天前
|
Linux C++
Linux c/c++进程间通信(1)
这篇文章介绍了Linux下C/C++进程间通信的几种方式,包括普通文件、文件映射虚拟内存、管道通信(FIFO),并提供了示例代码和标准输入输出设备的应用。
17 0
Linux c/c++进程间通信(1)
|
21天前
|
Linux C++
Linux c/c++之进程的创建
这篇文章介绍了在Linux环境下使用C/C++创建进程的三种方式:system函数、fork函数以及exec族函数,并展示了它们的代码示例和运行结果。
23 0
Linux c/c++之进程的创建
|
29天前
|
网络协议 Linux
linux学习之套接字通信
Linux中的套接字通信是网络编程的核心,允许多个进程通过网络交换数据。套接字提供跨网络通信能力,涵盖本地进程间通信及远程通信。主要基于TCP和UDP两种模型:TCP面向连接且可靠,适用于文件传输等高可靠性需求;UDP无连接且速度快,适合实时音视频通信等低延迟场景。通过创建、绑定、监听及读写操作,可以在Linux环境下轻松实现这两种通信模型。
28 1
|
15天前
|
Linux 开发工具
【Linux快速入门(二)】Linux与ROS学习之编译基础(make编译)
【Linux快速入门(二)】Linux与ROS学习之编译基础(make编译)
|
2月前
|
Linux Shell
6-9|linux查询现在运行的进程
6-9|linux查询现在运行的进程