进程等待+替换

✨MyShell实现✨
c++并发编程(书籍)

✨进程等待
 ✨wait/waitpid
  ✨代码示例
 ✨coredump
  ✨什么是coredump
  ✨开启coredump功能
  ✨示例代码
  ✨退出码
✨进程替换
 ✨原理
 ✨进程替换接口一览
 ✨实现一个shell
 ✨myshell反思
✨参考文章

在这里插入图片描述

✨进程等待

✨wait/waitpid

#include <sys/wait.h>
pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid, int *stat_loc, int options);
  1. pid = -1, 表示等待任意进程退出
    pid > 0和wait等价等待子进程
  2. stat_loc : 保存退出状态;可以传入nullptr,表示不保存退出状态
  3. options = 0 , 阻塞等待
    WONHANG,如果子进程没有退出,不进行阻塞等待直接返回0
    子进程结束,返回子进程pid
  4. WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。
    进程调用exit/ _exit函数退出——正常终止
    信号退出——不正常终止
    WEXITSTATUS(status): 若WIFEXITED非零(进程退出),提取子进程退出码。
    WTERMSIG(status):不正常退出时获取退出信号
✨代码示例

此处只分析不正常退出的情况

#include <iostream>
#include <sys/wait.h>
#include <unistd.h>
using namespace std;int main()
{int id = fork();if(id==0){// 子进程// puts("正常退出");// exit(0);while(1) ;}else{// 父进程cout<< id <<endl;int status=0;waitpid(id,&status,0);if(WIFEXITED(status)==0){// 不正常退出cout<< WTERMSIG(status)<<endl;}else{cout << WEXITSTATUS(status)<<endl;}}return 0;
}

在这里插入图片描述

✨coredump

✨什么是coredump

我们知道所有的程序最终运行起来,都会变成进程,进程在运行时可能会异常终止或崩溃,而Linux操作系统会将程序当时的内存状态记录下来,保存在一个文件中,这种行为就叫做Core Dump(中文有的翻译成核心转储)。(信号也是异常终止)

✨开启coredump功能

在没有开启之前计算机是无法使用这个功能的
配置信息——只介绍只能使用一次的配置

ulimit -c 1024 设置写入的文件大小
sudo sysctl -w kernel.core_pattern=/tmp/core-%e-%s-%u-%g-%p-%t 配置文件存放路径
生成的文件在/tem下的以core开头的文件
sudo sysctl -p 使配置立即生效

✨示例代码
#include <iostream>
#include <sys/wait.h>
#include <unistd.h>
using namespace std;int main()
{int id = fork();if(id==0){// 子进程// puts("正常退出");// exit(0);// while(1) ;int* p=nullptr;*p=8;}else{// 父进程cout<< id <<endl;waitpid(id,&status,0);}return 0;
}

在这里插入图片描述

✨退出码

在这里插入图片描述
对于waitpid的status并不是我们认为的int32位,存储的数据只有16位
开启coredump功能,异常终止coredump会置为1;不开启什么也看不到

✨进程替换

✨原理

子进程会继承父进程的环境变量

主进程替换
请添加图片描述

子进程替换
请添加图片描述

✨进程替换接口一览

#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...);
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 execvpe(const char *file, char *const argv[], char *const envp[]);

arg——如何使用命令如何传参
l ——列表形式传参,path:目标替换文件的具体文件路径,一定是以NULL结尾
p——不需要指明路径,file:目标替换文件的文件名
e——可以传递环境变量
v——将命令使用参数以数组的形式传参,一定是以NULL结尾

✨ 实现一个shell

#include<iostream>
#include<string.h>using namespace std;
#include<unistd.h>
#include<sys/wait.h>
#include<stdio.h>
#include<stdlib.h>// string op;
char* command[30];
char s[100];// 接收输入,防止strtok返回局部变量地址void GetUserOp()
{// getline(cin,op);// puts("读取成功");// cout<<op<<endl;// char s[100];fgets(s,sizeof(s),stdin);// 会将\n读入s[strlen(s)-1]='\0';int cnt=0;memset(command,0,sizeof(command));// char* str = (char*)op.c_str();command[cnt++] = strtok(s ," ");while(command[cnt++] = strtok(NULL," ")) ;// command 数据类型存的是指针,如果是局部的s进行接收输入的话// strtok返回的是这个接收数据的字符位置的指针// 如果是局部的话,就会造成数据丢失// printf("%p\n",s); // printf("%p\n",command[0]);// command[cnt-1]=NULL;// cout<< &command[0]<<endl;// while(i<op.size())// {//     // string tem;//     // while(i<op.size() && op[i]!=' ')//     // {//     //     tem+=op[i++];//     // }//     // i++;//     // if(cnt == 0)//     // {//     //     tem = string("/usr/bin/") + tem;//     // }//     // command[cnt++] = tem.c_str();//     // strcpy(command[cnt++],tem.c_str());//     // cout<<command<<endl;//     // cout<<cnt-1 << "-->" << command[cnt-1]<<endl;// }
}
void DoCommand()
{if(!strcmp(command[0],"ls")){execvp(command[0],command);}else if(!strcmp(command[0],"cd")){chdir(command[1]);char* pwd;// char* cwd;char cwd[100];getcwd(cwd,sizeof(cwd));sprintf(pwd,"PWD=%s",cwd);// 必须要使用pwd将环境变量进行改变,不能多加空格// 必须和环境变量格式完全一致// cout<<pwd<<endl;putenv(pwd);// 将环境变量的路径设置完美}else if(!strcmp(command[0],"env")){int cnt=0;while(environ[cnt])cout<<environ[cnt++]<<endl;}else if(!strcmp(command[0],"echo")){if(command[1]==NULL) {puts("");return;}else if(command[1][0]=='$'){char* val = command[1]+1;if(!strcmp(val,"?")){// 上次程序的返回值需要记录}else{char* ret = getenv(val);cout<<ret<<endl;}}else cout<<command[1]<<endl;}else if(!strcmp(command[0],"export")){if(command[1] == NULL) return;putenv(command[1]);}else{execvp(command[0],command);}// puts("..");// 进程替换之后,他不可能运行出来的
}
int main()
{while(1){pid_t id = fork();if(id==0){GetUserOp();// cout<<command[0]<<endl;// puts("--");DoCommand();}else{// 主进程waitpid(id,nullptr,0);}}// 不能在子进程中只读取一次,虽然你有个循环// 但是你的子进程替换完之后就回不来了,就没有循环了// pid_t id = fork();// if(id==0)// {//     puts("进程替换开始");//     // chdir("/usr/bin");// 更换工作路径//     while(1)//     {//         GetUserOp();//         puts("**");//         DoCommand();//     }return 0;
}

✨ myshell实现反思

  1. 不能先fork然后子进程中添加一个while循环进行替换,这样子好像是进行可以替换完一次再回来替换第二次,事实上是替换会将子进程的代码替换掉,也就是while没有了,替换完结束后直接被主进程捕获,终止程序
    错误代码
    // 不能在子进程中只读取一次,虽然你有个循环// 但是你的子进程替换完之后就回不来了,就没有循环了// pid_t id = fork();// if(id==0)// {//     puts("进程替换开始");//     // chdir("/usr/bin");// 更换工作路径//     while(1)//     {//         GetUserOp();//         puts("**");//         DoCommand();//     }

正确代码

    while(1){pid_t id = fork();if(id==0){GetUserOp();// cout<<command[0]<<endl;// puts("--");DoCommand();}else{// 主进程waitpid(id,nullptr,0);}}

  1. strtok函数
    char *strtok(char *str, const char *delim);
    他能将字符串进行按照指定的方式切割,并且返回char*(也就是切割出来的字符串)
    当完全被切割完的时候就会返回NULL,这个刚好可以被接收当列表中的最后一个参数
    错误代码分析
    // char s[100];fgets(s,sizeof(s),stdin);// 会将\n读入s[strlen(s)-1]='\0';int cnt=0;memset(command,0,sizeof(command));// char* str = (char*)op.c_str();command[cnt++] = strtok(s ," ");while(command[cnt++] = strtok(NULL," ")) ;

如果使用局部变量进行接收输入,再切割出字符串进行返回时,他返回的也是局部的字符串中的字符所对应的地址,这样一来就出现问题了,command存的是局部变量的地址局部变量出了作用域就销毁了,这样一来就找不到切割好的字符串了——不能返回局部变量的地址/引用
正确代码
将s设置为全局变量

char* command[30];
char s[100];// 接收输入,防止strtok返回局部变量地址void GetUserOp()
{// getline(cin,op);// puts("读取成功");// cout<<op<<endl;// char s[100];fgets(s,sizeof(s),stdin);// 会将\n读入s[strlen(s)-1]='\0';int cnt=0;memset(command,0,sizeof(command));// char* str = (char*)op.c_str();command[cnt++] = strtok(s ," ");while(command[cnt++] = strtok(NULL," ")) ;
}

  1. chdir函数——更待工作路径
#include<unistd.h>
int chdir(const char *path);

getenv函数——获得当前环境的环境变量
putenv函数——设置当前环境的环境变量

#include<stdlib.h>
char *getenv(const char *name);	
int putenv(char *string);

错误代码
子进程会继承父进程的环境变量

    else if(!strcmp(command[0],"cd")){chdir(command[1]);}

如果只写这一句,虽然他的工作路径已经更改了,但是环境变量并没有一同改变,就会出现一个很神奇的现象,你的pwd路径和环境变量路径不一致的问题

正确代码

    else if(!strcmp(command[0],"cd")){chdir(command[1]);char* pwd;// char* cwd;char cwd[100];getcwd(cwd,sizeof(cwd));sprintf(pwd,"PWD=%s",cwd);// 必须要使用pwd将环境变量进行改变,不能多加空格// 必须和环境变量格式完全一致// cout<<pwd<<endl;putenv(pwd);// 将环境变量的路径设置完美}
  1. 补充
    当我们需要输出环境变量的时候,可以使用extern char **environ; 进行输出

✨参考文章

开启coredump功能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/783284.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单链表就地逆置

算法思想&#xff1a;构建一个带头结点的单链表L&#xff0c;然后访问链表中的每一个数据结点&#xff0c;将访问到的数据结点依此插入到L的头节点之后。 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> typedef int ElemType; typedef s…

【学习】软件科技成果鉴定测试有何作用

软件科技成果鉴定测试是针对软件进行项目申报、科技成果鉴定等相关目的进行的测试。软件测试报告可作为项目申报、科技成果鉴定等工作的依据之一。软件类科技成果鉴定测试从软件文档、功能性、使用技术等方面对软件系统进行符合性测试。其测试结果证明软件的质量是否符合技术合…

智能指针(C++11)

智能指针的使用 问题 我们在平时写程序的时候&#xff0c;有些情况下不可避免地会遇见内存泄露的情况。内存泄露是指因为疏忽或错误&#xff0c;造成程序未能释放已经不再使用的内存的情况。例如下面这个例子&#xff0c;内存泄漏不易被察觉。 int div() {int a, b;cin >…

Vue tree自定义滚动条位置

贴一张效果图&#xff0c;我的效果不方便贴出来 实现支持&#xff1a; 1、懒加载 2、普通加载 下面贴关键思想&#xff1a; document有一个获取element元素的方法。 let element document.getElementById(tree); let arr document.querySelectorAll(".nodelModel&quo…

【JDK常用的API】包装类

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收藏 …

【IDEA】安装教程

目录 一、安装IDEA 二、激活IDEA 总结 一、安装IDEA 点击idea安装包->点击next->选择安装的路径->勾选创建桌面的快捷方式->勾选将bin目录添加到环境变量->勾选文件夹当做项目工程 打开下面这四个不勾选&#xff0c;勾选表示打开文件将以下面的格式打开 安装…

Python绘制线图之plt.plot()的介绍以及使用

在Python中plt.plot是matplotlib库中的一个函数,用于绘制点和线,并对其样式进行控制,下面这篇文章主要给大家介绍了关于Python绘制线图之plt.plot()的介绍以及使用的相关资料,需要的朋友可以参考下 plt.plot() 是Matplotlib库中用于绘制线图&#xff08;折线图&#xff09;的主…

YOLOv9改进策略 :主干篇 | 南开大学提出LSKNet,遥感旋转目标检测新SOTA ,ICCV 2023

💡💡💡本文改进内容: 动态调整特征提取骨干的感受野,以便更有效地处理被检测大小物体的不同的检测能力,也就是说可以有效提升检测数据集当中存在大小目标的检测能力 改进结构图如下: 《YOLOv9魔术师专栏》将从以下各个方向进行创新: 【原创自研模块】【多组合点优…

OpenEuler华为欧拉系统安装教程及联网配置

OpenEuler简介 openEuler是一款开源操作系统。当前openEuler内核源于Linux&#xff0c;支持鲲鹏及其它多种处理器&#xff0c;能够充分释放计算芯片的潜能&#xff0c;是由全球开源贡献者构建的高效、稳定、安全的开源操作系统&#xff0c;适用于数据库、大数据、云计算、人工智…

java入门学习Day01

本篇文章主要是学会如何使用IDEA&#xff0c;和运行第一个java文件。 java环境安装&#xff1a;Windows下Java环境配置教程_windows java环境配置-CSDN博客 IDEA安装&#xff1a;IDEA 2023.2.5 最新激活码,注册码&#xff08;亲测好用&#xff09; - 异常教程 以上两个链接…

安装VS2022社区版

Visual Studio 2022 平台的使用 1.Visual Studio 的下载地址&#xff1a; https://visualstudio.microsoft.com/zh-hans/downloads/ 2.安装步骤简要记录 耐心等待安装完成 参考链接&#xff1a;Visual Studio 2022安装教程(非常详细)&#xff0c;从零基础入门到精通&…

Thinkphp - 详细实现网站系统登录功能,附带 Mysql 数据库设置、Web 前端展示界面、信息校验等(详细代码,即设计过程)

前言 登录功能&#xff0c;是我们几乎开发每个系统都必须的模块。 登录功能设计思路&#xff0c;主要包括几个方面。 用户输入网址展示登录页面用户输入用户名&#xff0c;密码等点击登录进行信息校验校验通过之后&#xff0c;记录用户登录信息&#xff0c;跳转指定页面用户校…

EI期刊和EI会议有哪些不同?别再傻傻分不清

EI工程索引是综合性检索机构&#xff0c;是三个著名学术检索系统之一&#xff0c;EI工程索引也分为EI期刊和EI会议&#xff0c;那么两者有哪些不同&#xff1f;作者又该如何选&#xff1f;本文系统分享一下相关的知识&#xff0c;仅供学术人员参考&#xff1a; 第一、文章质量不…

RCG自条件是如何添加到 Pixel Generator上的?

在自条件的训练过程中&#xff0c;需要将图像经过Pretrained encoder的表征Rep输入进已有的Pixel Generator上&#xff0c;目前RCG是向四种Pixel Generator上加入了自条件&#xff0c;关于它是如何将rep加到Pixel Generator上的&#xff0c;我来总结一下&#xff1a; 一、Pixel…

【前端Vue】Vue从0基础完整教程第4篇:面经PC端 - Element (下)【附代码文档】

Vue从0基础到大神学习完整教程完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;vue基本概念&#xff0c;vue-cli的使用&#xff0c;vue的插值表达式&#xff0c;{{ gaga }}&#xff0c;{{ if (obj.age > 18 ) { } }}&#xff0c;vue指令&#xff0c;综合…

树的重心——树的结构

树的重心是指对于某个点&#xff0c;将其删除后&#xff0c;可以使得剩余联通块的最大值最小。也就等价于一某个点为根的树&#xff0c;将根删除后&#xff0c;剩余的若干棵子树的大小最小。 例如下图的树的重心就是2。 性质&#xff1a; 性质一&#xff1a;重心的若干棵子树打…

Vue使用el-statistic和el-card显示大屏中的统计数据

​ 一、页面内容&#xff1a; <el-row :gutter"20"><el-col :span"6"><el-card class"box-card"><div><el-statisticgroup-separator",":precision"2":value"value2":title"tit…

【娱乐】战双帕弥什游戏笔记攻略

文章目录 Part.I IntroductionChap.I Information Part.II 新手攻略Chap.I 角色和武器挑选Chap.II 新手意识推荐 Part.II 阵容搭配Chap.I 一拖二Chap.II 毕业队 Reference Part.I Introduction 2019年12月5日全平台公测。 偶然间入坑战双&#xff0c;玩了几天&#xff0c;觉得…

elasticsearch基础应用

1._cat接口 | _cat接口 | 说明 | | GET /_cat/nodes | 查看所有节点 | | GET /_cat/health | 查看ES健康状况 | | GET /_cat/master | 查看主节点 | | GET /_cat/indices | 查看所有索引信息 | es 中会默认提供上面的几个索引&#xff0c;表头…

Hotspot虚拟机对象问题(对象头...对象创建)

目录 对象头 实例数据 对齐填充 对象是如何创建 对象头 在Hotspot虚拟机中&#xff0c;Java对象在内存中的布局大致可以分为三部分:对象头、实例数据和填充对齐。因为synchronized用的锁是存在对象头里的&#xff0c;这里我们需要重点了解对象头。如果对象头是数组类型则对…