目录
前言
关于进程控制,从创建进程的fork,进程等待对子进程进行回收在前面的博客中都有谈到。fork创建进程:子进程与父进程共用一份代码和数据,修改时进行写实拷贝。那如果我不希望创建的子进程依旧与父进程执行同一份代码,而是希望子进程能够执行一个全新的程序,那要怎么办呢???
使用fork的返回值将父子进程进行分流??? *
进程替换简单示范
先介绍一个进程替换接口,看看猪跑;
程序输出:
上面代码预期结果:打印进程的PID,进程替换,再打印进程的PID;实际结果:打印进程PID,进程替换,进程结束没有再打印进程PID。
根据上面输出结果不然分析,进程替换将进程的代码和数据都替换了 ,所以源代码后面的内容没有被执行。
那么进程的pcb结构体对象有没有被替换呢???
再看一段代码:
程序输出:
子进程进程替换后其PID并没有改变,说明进程的PCB对象用的还是原来的,只不过可能内部数据进行了一定的修改。
所以: 程序替换不会创建新的进程,而是将进程的代码和数据进行修改;execl后续的代码被替换了所以没有执行,如果替换失败才可能执行 。进程替换大致可以分为3个步骤:
进程替换后父进程仍然找到子进程的原因:子进程进行进程替换后,只有物理内存上进行了修改,子进程的PCB对象还是原来的,PID没有改变,所以父进程依旧可以拿着原来的PID找到子进程对其进行回收。
补充:程序替换后,CPU是怎么知道从哪里再开始执行的???
Linux下形成的可执行程序不是杂乱无章的,其有自己的格式—ELF,在可执行程序的起始位置有表头(专门存放可执行程序各个区段的起始位置),其中就记录了可执行程序的入口。
进程替换函数exec*
在Linux中进程替换的函数有很多,但是所以的接口都是以exec开头的,其中我们开发过程中最常用的有6个,看似很多但是基本上都是大同小异。下面对一一介绍。
想要执行一个可执行程序,分两步:
告诉操作系统可执行程序在哪; 告诉操作系统要怎么样执行这个程序。下面这些接口都是为了解决这两个问题,只不过处理的方式不一样。
int execl(const char* ,const char*,…)
int execl(const char*,const char* arg,…)第一个参数表示可执行程序的路径,在哪一个目录小;后面的参数是可变参数表示执行这个可执行程序需要带那些选项,相当于main函数的参数。
通过第一个参数告诉操作系统程序的位置,后面的可变参数告诉操作系统如何执行,注意:可变参数要以NULL结尾。
int execlp(const char*,const char* ,…)
int execlp(const char*,const char* arg,…)与上面接口相比,该函数的区别好像就是函数名称和参数名称不一样呀。
是的,execl第一个参数path是路径,而execpl第一个参数是file是文件名称。 execpl只有文件名称,那操作系统怎么知道找那个目录下查找这个文件 ,execpl接口默认了查找路径为环境变量PATH中的路径,就是指令存放的路径。
所以execpl函数就不需要指定路径,直接指定文件名称即可。所以如果先通过execpl进程替换为自己的可执行程序就要先将可执行程序添加到这些目录中,或将可执行程序所在的目录加到PATH下。
int execv(const char* path,char* const argc[])
第一个参数不用说跟上面的一样,还是指定路径。而后面不再是可变参数了,而是一个字符串数组和。execv将execl后面的可变参数进行了整合,以一个数组的方式进行传递。就是main函数参数中的char* argv。将后面的argv数组传递给可执行程序中main的参数进而执行。上面的可变参数在底层也会被转换成数组的形式。
int execvp(consy char* file,const char* arg[])
与execv区别在于其有默认查找文件的路径PATH,只需要指定可执行程序的名称即可。
int execle(const char* path.const arg,…,char* const envp[])
此接口与execl不同于后面多了一个参数envp,此接口运行我们在进程替换之后设置新进程的环境变量。
注意设置环境变量后,原本的环境变量会被覆盖。
总计
上面各个库函数名称的规律:
| 函数名 | 参数格式 | 是否带路径 | 是否使用当前环境变量 |
|---|---|---|---|
| 列表 | 不带 | 继承 | |
| 列表 | 带 | 继承 | |
| 列表 | 不带 | 自己组装 | |
| 数组 | 不带 | 继承 | |
| 数组 | 带 | 继承 | |
| 数组 | 不带 | 自己组装 |
exec可以去调用任何进程,不论是用什么语言进行编写的,只要是可实现程序,都能进行替换,exec相当于一个加载器,可以将各种程序加载起来 。
在execlv中可以指定的传环境变量,那么其他没有传环境环境变量的接口怎么办???
环境变量也是数据,在进程地址空间中也为环境环境变量和命令行参数分配了空间,子进程也会拷贝一份父进程的环境变量;当进行进程替换的时候如果没有指定修改或覆盖环境变量,那么环境依旧是原来替换之前的。
如果想要对替换后的进程的环境变量修改怎么办???
上面的execle是一种方法,但是还有一种方法:
补充:在上面有各种各样的函数实现进程替换,但是他们底层都调用同一个系统调用接口:execve(),上面的库函数都是对这个接口的封装而与。
Linux 下用select实现串口数据读取方法
在 Linux 系统里,我们可以借助 select、poll 或者 epoll 这些 I/O 多路复用机制达成串口数据读取的触发方式。这些机制能够让程序在特定文件描述符(像串口设备文件描述符)有数据可读时得到通知,进而进行数据读取操作,而不是像轮询方式那样持续调用 read 函数。
示例代码(使用 select 实现)
#include进程替换 Linux 服务配置实践之NTP时间同步与SSH免密登录#include #include #include #include #include // 设置串口波特率void SetSpeed(int fd, int speed) {struct termios options;tcgetattr(fd, &options);switch (speed) {case 115200:cfsetispeed(&options, B115200);cfsetospeed(&options, B115200);break;// 可以添加更多波特率设置default:cfsetispeed(&options, B115200);cfsetospeed(&options, B115200);break;}tcsetattr(fd, TCSANOW, &options);}// 设置串口参数void SetParity(int fd, int> 代码解释
通过这种方式,程序就无需持续轮询函数,而是在有数据到达时才进行读取操作。
以上就是【Linux手册】进程替换:从fork到exec揭秘进程替换的全流程的详细内容,更多相关资料请阅读主机测评网其它文章!














发表评论