Linux之进程替换
进程替换
- 1.什么是进程替换
- 2.替换函数
- 2.1 execl函数
- 2.2 execv函数
- 2.3 execlp函数
- 2.4 execvp函数
- 2.5 在自己的C程序上如何运行其他语言的程序?
- 2.6 execle 函数
- 2.7 小结
- 3.一个简易的shell
1.什么是进程替换
fork()之后,父子各自执行父进程代码的一部分,父子代码共享,数据写时拷贝各自一份,如果子进程想就执行一个全新的进程呢?
进程的程序替换,来完成这个功能。
程序替换:是通过特定的接口,加载磁盘上的一个权限的程序(代码和数据),加载到进程的地址空间中。
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exex函数以执行另外的一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新进程替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec函数前后进程的id并未改变。
所以,进程替换,并没有创建新的子进程,所谓的exec*函数,本质就是加载程序的函数。
2.替换函数
*exec 函数:**功能其实就是加载器的底层接口
2.1 execl函数
1 #include <stdio.h>2 #include <unistd.h>3 4 5 int main()6 {7 printf("当前进程的开始代码!\n");8 9 // execl("/usr/bin/ls","ls",NULL);10 // execl("/usr/bin/ls","ls","-l",NULL);11 execl("/usr/bin/ls","ls","-l","--color=auto","-a",NULL); 12 printf("当前进程的结束代码!\n"); 13 14 return 0; 15 }
运行结果:
[jyf@VM-12-14-centos 进程]$ ./mytest11
当前进程的开始代码!
. Makefile myproc.c mytest10 mytest2 mytest4
可见,并没有执行printf(“当前进程的结束代码!\n”);这条语句,进程发生了替换。
execl是程序替换,调用该函数成功之后,会将当前进程的所有代码和数据都进行替换!包括已经执行的和没有执行的!所以一旦调用成功,后续的所有代码都不会执行。
进程替换应用实例
1 #include <stdio.h>2 #include <stdlib.h>3 #include <unistd.h>4 #include <sys/wait.h>5 6 int main()7 {8 //为什么我要创建子进程?9 //如果不创建,我们替换的进程就是父进程,如果创建了,我们替换的进程就是子进程,而不影响父进程。10 //因为我们想让父进程聚焦在读取数据,解析数据,指派进程执行代码的功能! 11 12 //1.显示一个提示符:root@localhost# 13 //2.获取用户输入的字符串,fgets,scanf,-> ls -a -l14 //3.对字符串进行解析15 while(1) 16 { 17 pid_t id = fork();18 if(id == 0) 19 { 20 //子进程 21 printf("子进程开始运行,pid:%d\n",getpid());22 sleep(3); 23 execl("/usr/bin/ls","ls","-a","-l",NULL);24 exit(1); 25 } 26 else{ 27 ;//父进程 28 printf("父进程开始运行:%d\n",getpid()); 29 int status = 0; 30 pid_t id = waitpid(-1,&status,0);//阻塞等待,一定是子进程先运行完毕,然后父进程获取之后,才退出!31 if(id>0) 32 { 33 printf("wait success,exit code:%d\n",WEXITSTATUS(status));34 } 35 } 36 } 37 return 0;38 }
加载新程序之前,父子进程的代码和数据的关系?代码共享,数据写时拷贝。
当子进程加载新程序的时候,不就是一种写入吗?代码要不要写时拷贝呢?将父子进程的代码分离?必须分离。
int execl(const char* path,const char* arg,…); 父子进程在代码和数据上就彻底分开了,虽然曾经并不冲突。
2.2 execv函数
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h> int main()
{ pid_t id = fork(); if(id == 0) { printf("子进程开始运行:%d\n",getpid()); char* const _argv[] = {(char*)"ls",(char*)"-a",(char*)"-l",NULL}; execv("/usr/bin/ls",_argv); exit(1); } else { printf("父进程开始运行:%d\n",getpid()); int status =0; pid_t id = waitpid(-1,&status,0); if(id>0) { printf("wait success,exit code:%d\n",WEXITSTATUS(status)); } } return 0;
}
运行结果:
[jyf@VM-12-14-centos lesson3-28]$ ./mytest
父进程开始运行:26522
子进程开始运行:26523
total 36
drwxrwxr-x 2 jyf jyf 4096 Mar 28 22:45 .
drwx------ 19 jyf jyf 4096 Mar 28 17:26 ..
-rwxrwxr-x 1 jyf jyf 8616 Mar 28 22:45 mytest
-rwxrwxr-x 1 jyf jyf 8616 Mar 28 21:57 mytest1
-rw-rw-r-- 1 jyf jyf 532 Mar 28 22:45 test1.c
wait success,exit code:0
2.3 execlp函数
要执行程序,必须先找到程序!带路径,不带路径都能找到吗?只要在环境变量中存在即可。
我会自己在环境变量PATH中进行查找,你不用告诉我你要执行的程序在哪里!!
2.4 execvp函数
// int execvp(const char *file, char *const argv[]);
execvp("ls",_argv);
const char* file:具体要执行的程序,它会到环境变量里面去找
具体实施方法如execv函数。
2.5 在自己的C程序上如何运行其他语言的程序?
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> const char* myfile = "/home/jyf/lesson3-28/mycmd"; int main() { pid_t id = fork(); if(id == 0) { printf("子进程开始运行:%d\n",getpid());
W> char* const _argv[] = {(char*)"ls",(char*)"-a",(char*)"-l",NULL}; // execv("/usr/bin/ls",_argv); //execlp("ls","ls","-a","-l",NULL); //execvp("ls",_argv); //execl(myfile,"mycmd","-a",NULL); //execlp("python","python","test.py",NULL); //运行python程序 //execl("/usr/bin/python","python","test.py",NULL); //运行python程序execlp("bash","bash","test.sh",NULL); //运行shell程序 exit(1); } else { printf("父进程开始运行:%d\n",getpid()); int status =0; pid_t id = waitpid(-1,&status,0); if(id>0) { printf("wait success,exit code:%d\n",WEXITSTATUS(status)); } } return 0; }
2.6 execle 函数
int execle(const char *path, const char *arg, ..., char * const envp[]);
char* const envp[ ]:将环境变量传递给要替换的程序
2.7 小结
命名理解:这些函数看起来很容易混,但只要掌握规律就很好记。
l(list):表示参数要自己给具体路径
v(vector):表示可变参数都放到数组中
p(path):有p自动在环境变量中搜索PATH
e(env):表示自己创建维护环境变量,将环境变量传递给要替换的进程
为什么要替换?
一定和应用场景有关,我们有时候必须让子进程执行新的程序
3.一个简易的shell
#include <stdio.h> #include <stdlib.h>#include <unistd.h>#include <sys/wait.h>#include <sys/types.h>#include <string.h>#define NUM 1024#define SIZE 32#define SEP " "//保存完整的命令行字符串char cmd_line[NUM];//保存打散之后的命令行字符串char* g_argv[SIZE];//shell 运行原理:父进程读取命令,解析命令,派发给子进程命令,让子进程去执行命令int main(){//0.命令行解释器,一定是一个常驻内存的进程,不退出while(1){//1.打印出提示信息,[root@localhost myshell]#printf("[root@localhost myshell]# ");fflush(stdout);memset(cmd_line,'\0',sizeof(cmd_line));//2.获取用户的键盘输入[输入的是各种指令和选项: "ls -a -l -i"]if(fgets(cmd_line,sizeof(cmd_line),stdin) == NULL){continue;}cmd_line[strlen(cmd_line)-1] = '\0';//将回车键'\n',替换成'\0'//"ls -a -l -i\n\0"// printf("echo %s\n",cmd_line);g_argv[0] = strtok(cmd_line,SEP);//将输入的字符串按空格进行分割,第一次调用,要传入原始字符串int index = 1;if(strcmp(g_argv[0],"ls") == 0) //ls自带调色实现{
W> g_argv[index++] = "--color=auto";}if(strcmp(g_argv[0],"ll") == 0) //ll命令的简写的实现{
W> g_argv[0] = "ls";
W> g_argv[1] = "-l";
W> g_argv[2] = "--color=auto";index+=2;}
W> while(g_argv[index++] = strtok(NULL,SEP));//第二次调用,如果还要解析原始字符串,传入NULL//for debug//for(index =0;g_argv[index];index++)//{//procrintf("g_argv[%d]: %s\n",index,g_argv[index]);//}//4.TODO,内置命令,让父进程自己执行的命令,我们叫内置命令,内建命令//内建命令本质其实就是shell中的一个函数调用if(strcmp(g_argv[0],"cd") == 0) //not child execute ,father execute{if(g_argv[1]!=NULL){chdir(g_argv[1]); //cd path}continue;}//5.fork()pid_t id = fork();if(id ==0){//procrintf("下面功能让子进程进行的\n");execvp(g_argv[0],g_argv); exit(1);}}//fatherint status = 0;pid_t ret = waitpid(-1,&status,0);if(ret>0){//printf("exit code:%d\n",WEXITSTATUS(status));}}return 0;}
相关文章:
Linux之进程替换
进程替换1.什么是进程替换2.替换函数2.1 execl函数2.2 execv函数2.3 execlp函数2.4 execvp函数2.5 在自己的C程序上如何运行其他语言的程序?2.6 execle 函数2.7 小结3.一个简易的shell1.什么是进程替换 fork()之后,父子各自执行父进程代码的一部分&…...
关于清除浮动
浮动最早是用来做图文排版,为了让块级元素同行显示,而html中块元素是有自己的排列规则,一般独占一行。所以有了浮动元素,一旦元素浮动了就会脱离文档流,产生问题。怎么去清除浮动:(1)…...
Uber H3 index 地图索引思考
H3 是 uber 设计的六边形空间索引,go 语言操作包是 h3-go,可以通过经纬度获取所在的 h3 六边形边界,每个经纬度对应的六边形都是确定的,每个六边形唯一对应了一个 h3index。在业务开发中,我们可以通过 h3index 来对地理…...
多线程的几种状态
Java-多线程的几种状态🔎1.NEW( 系统中线程还未创建,只是有个Thread对象)🔎2.RUNNABLE( (就绪状态. 又可以分成正在工作中和即将开始工作)🔎3.TERMINATED(系统中的线程已经执行完了,Thread对象还在)🔎4.TIMED_WAITING(指定时间等待…...
【算法题】1574. 删除最短的子数组使剩余数组有序
题目: 给你一个整数数组 arr ,请你删除一个子数组(可以为空),使得 arr 中剩下的元素是 非递减 的。 一个子数组指的是原数组中连续的一个子序列。 请你返回满足题目要求的最短子数组的长度。 示例 1: …...
理解对数——金融问题中的自然对数(以e为底的对数)
第3章 金融问题(Financial Matters)——金融问题中的自然对数If thou lend moneyto any ofMy people. ...thou shalt not beto him as a creditor;neither shall yelay upon him interest.(如果你借钱给我的任何人。 ……你不应该是他的债权人;也不可向他加息。)——…...
vue2进阶学习之路
HTML、CSS和JavaScript基础 在学习Vue2之前,需要掌握HTML、CSS和JavaScript的基础知识。包括HTML的标签、CSS的布局和样式、JavaScript的变量类型、条件语句、循环语句等。 Vue2的基础知识 掌握Vue2的基本概念和语法,包括Vue2实例、数据绑定、指令、组件…...
决策树ID3算法
1. 决策树ID3算法的信息论基础 机器学习算法其实很古老,作为一个码农经常会不停的敲if, else if, else,其实就已经在用到决策树的思想了。只是你有没有想过,有这么多条件,用哪个条件特征先做if,哪个条件特征后做if比较优呢&#…...
C++模板基础(一)
函数模板(一) ● 使用 template 关键字引入模板: template void fun(T) {…} – 函数模板的声明与定义 – typename 关键字可以替换为 class ,含义相同 – 函数模板中包含了两对参数:函数形参 / 实参;模板形…...
生产者消费者模型线程池(纯代码)
目录 生产者消费者模型 条件变量&&互斥锁(阻塞队列) makefile Task.hpp BlockQueue.hpp BlockQueueTest.cc 信号量&&互斥锁(环形队列) makefile RingQueue.hpp RingQueueTest.cc 线程池(封…...
K8s 应用的网络可观测性: Cilium VS DeepFlow
随着分布式服务架构的流行,特别是微服务等设计理念在现代应用普及开来,应用中的服务变得越来越分散,因此服务之间的通信变得越来越依赖网络,很有必要来谈谈实现微服务可观测性中越来越重要的一环——云原生网络的可观测。K8s 是微服务设计理念能落地的最重要的承载体,本文…...
3.29面试题
文章目录内存内存管理执行过程要点面试题内存 内存管理 由JVM管理 堆:new出来的对象(包括成员变量、数组元素、方法的地址)栈:局部变量(包括方法的参数)方法区:.class字节码文件(…...
操作系统漏洞发现
操作系统漏洞发现前言一、操作系统漏洞发现1.1 namp2. Goby3. Nessus二,进行渗透测试2.1 使用工具进行渗透1. metasploit2.2 EXP2.3 复现文章三,操作系统漏洞修复前言 不管是对于App来说,还是web站点来说,操作系统是必须的&#x…...
Linux gdb调试底层原理
TOC 前言 linux下gdb调试程序操作过程参考本人文章:gdb调试操作; 这里不再叙述; 本文主要内容是介绍GDB本地调试的底层调试原理,我们来看一下GDB是通过什么机制来控制被调试程序的执行顺序; 总结部分是断点调试的底层原理,可以直接跳转过去先看看大概…...
LC-1647. 字符频次唯一的最小删除次数(哈希+计数)
1647. 字符频次唯一的最小删除次数 难度中等56 如果字符串 s 中 不存在 两个不同字符 频次 相同的情况,就称 s 是 优质字符串 。 给你一个字符串 s,返回使 s 成为 优质字符串 需要删除的 最小 字符数。 字符串中字符的 频次 是该字符在字符串中的出现…...
HTTP状态码
100: 接受,正在继续处理 200: 请求成功,并返回数据 201: 请求已创建 202: 请求已接受 203: 请求成为,但未授权 204: 请求成功,没有内容 205: 请求成功,重置内容 206: 请求成功,返回部分内容 301: 永久性重定…...
【Linux】初见“which命令”,“find命令”以及linux执行命令优先级
文章目录1.which命令1.1 whereis命令1.2 locate命令1.3 搜索文件命令总结2.find命令2.1 find之exec用法2.2 管道符之xargs用法3 Linux常用命令4.命令执行优先级1.which命令 查找命令文件存放目录 搜索范围由环境变量PATH决定(echo $PATH) which命令格式࿱…...
update case when 多字段,多条件, mysql中case when用法
文章目录 前言 sql示例 普通写法: update case when写法 update case when 多字段写法 case when语法 case when 的坑 1、不符合case when条件但是字段被更新为null了 解决方法一:添加where条件 解决方法二:添加else 原样输出 2、同一条数据符…...
mysql隐式转换 “undefined“字符串匹配到mysql int类型0值字段
描述:mysql 用字符串搜索 能搜到int类型查询结果 mysql int类型条件用字符串查询 table: CREATE TABLE all_participate_records (id bigint unsigned NOT NULL AUTO_INCREMENT,created_at datetime(3) DEFAULT NULL,updated_at datetime(3) DEFAULT NULL,deleted…...
Redis八股文
1.Redis是什么? Redis 是一个基于 C 语言开发的开源数据库(BSD 许可),与传统数据库不同的是 Redis 的数据是存在内存中的(内存数据库),读写速度非常快,被广泛应用于缓存方向。并且,…...
InnoDB——详细解释锁的应用,一致性读,自增长与外键
一致性非锁定读 一致性的非锁定读(consistent nonlocking read)是指InnoDB存储引擎通过行多版本控制的方式读取当前执行时数据库中行的数据。 如果读取的行正在执行 行Delete或Update操作,这时读取操作不会因此去等待行上锁的释放。相反&…...
C++模板基础(四)
函数模板(四) ● 函数模板的实例化控制 – 显式实例化定义: template void fun(int) / template void fun(int) //header.h template<typename T> void fun(T x) {std::cout << x << std::endl; }//main.cpp #include&quo…...
pycharm使用记录
文章目录下载安装后续其他设置编辑器设置关于debug下载安装 直接去pycharm官网下载社区版,这个版本本来就是免费的,而且功能其实已经够了 后续其他设置 首先,第一次启动时,记得在preference->interpreter中设置python环境&a…...
Linux命令·kill·killall
Linux中的kill命令用来终止指定的进程(terminate a process)的运行,是Linux下进程管理的常用命令。通常,终止一个前台进程可以使用CtrlC键,但是,对于一个后台进程就须用kill命令来终止,我们就需…...
Linux /proc/version 文件解析
/proc/version文件里面的内容: Linux version 4.14.180-perf (oe-user@oe-host) (clang version 10.0.5 for Android NDK, GNU ld (GNU Binutils) 2.29.1.20180115) #1 SMP PREEMPT Wed Mar 29 18:55:02 CST 2023 /proc/version文件里面记录了如下内容: 1、Linux kernel的…...
【Django 网页Web开发】15. 实战项目:管理员增删改查,md5密码和密码重置(08)(保姆级图文)
目录1. model编写数据表2. 管理员列表2.1 admin.py视图文件2.2 admin_list.html2.3 url.py2.4 最终效果3. 管理员添加3.0 md5包的书写3.1 form.py表单组件3.2 admin.py视图文件3.3 引入公共的添加数据html3.4 url.py3.5 最终效果4. 管理员编辑4.0 form表单组件4.1 admin.py视图…...
STL容器之<array>
文章目录测试环境array介绍头文件模块类定义对象构造初始化元素访问容器大小迭代器其他函数测试环境 系统:ubuntu 22.04.2 LTS 64位 gcc版本:11.3.0 编辑器:vsCode 1.76.2 array介绍 array是固定大小的序列式容器,它包含按严格…...
flask教程6:cookie和session
文章目录一、cookie1.1 什么是cookie?1.2 使用cookie1.2.1 设置cookie1.2.2设置cookie的有效期1.2.3在Flask中查询cookie1.2.4删除cookie二、session2.1实现session的两种思路2.1.1 第一种2.1.2 第二种2.2使用session2.2 .1设置session2.2.2 设置有效期2.2.3 获取se…...
【JavaEE初阶】第六节.网络原理TCP/IP协议
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一、TCP/IP协议五层协议栈; 1.1 应用层协议; 二、传输层协议; 2.1 UDP协议; 2.2 TCP协议; 2.…...
模式识别 —— 第六章 支持向量机(SVM)与核(Kernel)
模式识别 —— 第六章 支持向量机(SVM)与核(Kernel) 文章目录模式识别 —— 第六章 支持向量机(SVM)与核(Kernel)硬间隔(Hard-Margin)软间隔(Soft…...
中国平安网站建设/怎么找当地的地推团队
一个简单的 HTML 表单下面的例子显示了一个简单的 HTML 表单,它包含两个输入字段和一个提交按钮:实例Name: E-mail: 运行实例当用户填写此表单并点击提交按钮后,表单数据会发送到名为 "welcome.php" 的 PHP 文件供处理。表单数据是…...
网站 http 状态码返回值 301/seo分析网站
修改后代码如下 #define _CRT_SECURE_NO_WARNINGS #pragma once // stdafx.h : 标准系统包含文件的包含文件, // 或是经常使用但不常更改的 // 特定于项目的包含文件 //#pragma once// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。// 如果要为以前的 W…...
河南省人民政府门户网站/优化网站标题
1)获取当前日期 首先近N个月,是以当前执行时间为基期的,所以先弄清楚在oracle中如何获取当前日期。 select sysdate from dual 执行了这条语句后,可以看到返回了一个当前日期 注意sysdate不是一个函数,所以后面不要…...
番禺做网站600元/b2b平台网站
in 判断元素是否存在于容器当中 list1 [1, 2, 3] tuple1 (1, 2, 3) set1 {1, 2, 3} print(3 in list1) # True print(3 in tuple1) # True print(3 in set1) # True 如果要判断是否在set当中,要注意被判断的元素必须可以保存在set当中,如果是列表,字典,集合,则不能判断 …...
如何拥有自己的网站域名/推广普通话手抄报
题目描述; 给定一个没有重复数字的序列,返回其所有可能的全排列。 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 算法1:DFS class Solution { public:vector<vector<int>> permute(ve…...
wordpress搜索乱码/平台推广渠道
2019独角兽企业重金招聘Python工程师标准>>> 前言 人机交互简单来说,就是“人和机器打交道的方式”。人和计算机打交道根源于人类把计算机当成一种有效的计算服务工具。计算机自产生以来,计算能力日益强大,人类对计算机的态度也开…...