linux中学习控制进程的要点
1. 进程创建
1.1 fork函数
#include <unistd.h>
pid_t fork(void);
返回值:自进程中返回0,父进程返回子进程id,出错返回-1
进程调用fork,当控制转移到内核中的fork代码后,内核会做以下操作
- 分配新的内存块和内核数据结构给子进程
- 将父进程部分数据结构内容拷贝至子进程
- 添加子进程到系统进程列表当中
- fork返回,开始调度器调度
fork之前父进程独立执行,fork之后,父子两个执行流分别执行。注意,fork之后,谁先执行完全由调度器决定。
1.2 写时拷贝
通常,父子代码共享,父子再不写入时,数据也是共享的,当任意一方试图写入,就以写时拷贝的方式各自一份副本。具体见下图:
1.3 fork常规用法
- 一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。
- 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。
1.4 fork调用失败的原因
- 系统中有太多的进程
- 实际用户的进程数超过了限制
2.进程终止
2.1 进程退出场景
- 正常退出,异常退出
- 一个进程只有在正常退出的时候,返回值才是有意义的
- 若进程异常退出,返回值没有意义
2.2 进程常见退出方法
正常退出
- 1. 从main返回
- 2. 调用exit
- 3. _exit
2.3 异常退出
- 收到kill等异常信号
- 执行代码时出现错误,操作系统发送信号,随后通知的进程
exit函数和_exit函数
#include <unistd.h>
void _exit(int status);
void exit(int status);
- 参数:status 定义了进程的终止状态,父进程通过wait来获取该值
- 虽然status是int,但是仅有低8位可以被父进程所用。所以_exit(-1)时,在终端执行$?发现返回值 是255
exit最后也会调用_exit, 但在调用_exit之前,还做了其他工作:
1. 执行用户通过 atexit或on_exit定义的清理函数。
2. 关闭所有打开的流,所有的缓存数据均被写入
3. 调用_exit
2.4 return退出
return是一种更常见的退出进程方法。执行return n等同于执行exit(n),因为调用main的运行时函数会将main的返回值当做 exit的参数。
3. 进程等待
3.1意义:
- 子进程退出,父进程如果不管不顾,就可能造成‘僵尸进程’的问题,进而造成内存泄漏。
- 父进程派给子进程的任务完成的如何,我们需要知道。如,子进程运行完成,结果对还是不对, 或者是否正常退出。
- 父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息
3.2 方法
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);
返回值:成功返回被等待进程pid,失败返回-1。
参数:输出型参数,获取子进程退出状态,不关心则可以设置成为NULL
pid_ t waitpid(pid_t pid, int *status, int options);
返回值:当正常返回的时候waitpid返回收集到的子进程的进程ID;如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:pid:Pid=-1,等待任一个子进程。与wait等效。Pid>0.等待其进程ID与pid相等的子进程。status:WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)options:WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进
程的ID。
- 如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程退
- 出信息。
- 如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞。
- 如果不存在该子进程,则立即出错返回。
3.3 获取子进程status
wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
如果传递NULL,表示不关心子进程的退出状态信息。
否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。
status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特
位):
status解引用后是int型变量,占据四个字节的内存空间。但它的四个字节并不是都存储着进程的退出返回值。如图所示:我们给每个字节从高地址到低地址依次编号:1、2、3、4字节。
一个进程退出的场景只有两个
正常退出和异常退出
3.3.1 位运算法
因此在获取返回值之前,先通过低七位判断进程是否正常退出
- 判断是否正常退出:如果status & 0x7f == 0就能判断一个进程是正常退出,否则就是异常退出
- 解释:因为异常退出码占用的是4号字节中的低7位,因此我们可以通过(*status)和16进制数(0x7f)进行与运算得到异常退出码。
- 在判断返回值有意义后,取出低16位中的高8位
- 取出方法:(status >> 8) & 0xff的结果
- 解释:我想取出低16位中的高8位,需要先将status右移8位,随后与1111 1111进行按位与,得到结果
因为返回值只用了一个字节保存,因此进程的返回值最好不要大于255
3.3.2 宏函数
WIFEXITED(status) 等价于 ( (*status)&(0x7f) )==0 ,当异常退出码是0,宏函数返回true,表示进程的退出返回值有意义
WEXITSTATUS(status) 等价于 ( (*status >> 8)&(0xff) ),这样直接就可以得到进程的退出返回值。
二进制十进制十六进制的转换方法
教你快速学会二进制、十进制、十六进制之间的转换 - 知乎 (zhihu.com)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{pid_t pid;pid = fork();if (pid < 0){printf("%s fork error\n", __FUNCTION__);return 1;}else if (pid == 0){ // childprintf("child is run, pid is : %d\n", getpid());sleep(5);exit(1);}else{int status = 0;pid_t ret = 0;do{ret = waitpid(-1, &status, WNOHANG); // 非阻塞式等待if (ret == 0){printf("child is running, i have some task\n");}sleep(1);} while (ret == 0);if (WIFEXITED(status) && ret == pid){printf("wait child 5s success, child return code is :%d.\n", WEXITSTATUS(status));}else{printf("wait child failed, return.\n");return 1;}}return 0;
}
4. 进程的程序替换
4.1 替换原理
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数 以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动 例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
替换函数 其实有六种以exec开头的函数,统称exec函数:
#include <unistd.h>`
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 execve(const char *path, char *const argv[], char *const envp[]);
- 这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
- 如果调用出错则返回-1
- 所以exec函数只有出错的返回值而没有成功的返回值。
4.2 命名理解
l(list) : 表示参数采用列表
v(vector) : 参数用数组
p(path) : 有p自动搜索环境变量PATH
e(env) : 表示自己维护环境变量
#include <unistd.h>
int main()
{char *const argv[] = {"ps", "-ef", NULL};char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};execl("/bin/ps", "ps", "-ef", NULL);// 带p的,可以使用环境变量PATH,无需写全路径execlp("ps", "ps", "-ef", NULL);// 带e的,需要自己组装环境变量execle("ps", "ps", "-ef", NULL, envp);execv("/bin/ps", argv);// 带p的,可以使用环境变量PATH,无需写全路径execvp("ps", argv);// 带e的,需要自己组装环境变量execve("/bin/ps", argv, envp);exit(0);
}
事实上,只有execve是真正的系统调用,其它五个函数最终都调用 execve,所以execve在man手册 第2节,其它函数在 man手册第3节。
5. 制作做一个简易的shell
相关文章:

linux中学习控制进程的要点
1. 进程创建 1.1 fork函数 #include <unistd.h> pid_t fork(void); 返回值:自进程中返回0,父进程返回子进程id,出错返回-1 进程调用fork,当控制转移到内核中的fork代码后,内核会做以下操作 分配新的内存块和…...
C++Qt QSS要注意的坑
qss源自css,相当于css的一个子集,主要支持的是css2标准,很多网上的css3的标准的写法在qss这里是不生效的,所以不要大惊小怪。 qss也不是完全支持所有的css2,比如text-align官方文档就有说明,只支持 QPushB…...
LeetCode每日一题:56. 合并区间(2023.8.27 C++)
目录 56. 合并区间 题目描述: 实现代码与解析: 排序 贪心 原理思路: 56. 合并区间 题目描述: 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&…...

电视盒子什么牌子好?经销商整理线下热销电视盒子品牌排行榜
在面对众多品牌和型号时,不知道电视盒子哪个牌子好的消费者超多,很多人进店都会问我电视盒子哪款好?我根据店铺内近两年的销量情况整理了电视盒子品牌排行榜,看看实体店哪些电视盒子最值得入手吧。 TOP 1.泰捷WEBOX 40Pro Max电视…...

JavaScript关于函数的小挑战
题目 回到两个体操队,即海豚队和考拉队! 有一个新的体操项目,它的工作方式不同。 每队比赛3次,然后计算3次得分的平均值(所以每队有一个平均分)。 只有当一个团队的平均分至少是另一个团队的两倍时才会获胜。否则&…...

机器学习深度学习——针对序列级和词元级应用微调BERT
👨🎓作者简介:一位即将上大四,正专攻机器学习的保研er 🌌上期文章:机器学习&&深度学习——NLP实战(自然语言推断——注意力机制实现) 📚订阅专栏:机…...
重启Mysql时报错rm: cannot remove ‘/var/lock/subsys/mysql‘: Permission denied
只有用mysql重启时报错,用root不报错 [mysqlt3-dtpoc-dtpoc-web04 bin]$ service mysql restart Shutting down MySQL.. SUCCESS! rm: cannot remove /var/lock/subsys/mysql: Permission denied Starting MySQL.. SUCCESS! [roott3-dtpoc-dtpoc-web04 ~]# serv…...

[C/C++]指针详讲-让你不在害怕指针
个人主页:北海 🎐CSDN新晋作者 🎉欢迎 👍点赞✍评论⭐收藏✨收录专栏:C/C🤝希望作者的文章能对你有所帮助,有不足的地方请在评论区留言指正,大家一起学习交流!ǹ…...

无涯教程-Android - Frame Layout函数
Frame Layout 旨在遮挡屏幕上的某个区域以显示单个项目,通常,应使用FrameLayout来保存单个子视图,因为在子视图彼此不重叠的情况下,难以以可扩展到不同屏幕尺寸的方式组织子视图。 不过,您可以使用android:layout_grav…...

docker desktop安装es 并连接elasticsearch-head:5
首先要保证docker安装成功,打开cmd,输入docker -v,出现如下界面说明安装成功了 下面开始安装es 第一步:拉取es镜像 docker pull elasticsearch:7.6.2第二步:运行容器 docker run -d --namees7 --restartalways -p 9…...

计网(第四章)(网络层)(六)
目录 一、路由选择协议(动态路由自动获取路由信息)概述: 二、因特网采用的路由协议 主要特点: 1.自适应 2.分布式 3.分层次 因特网采用分层次的路由选择协议: 三、常见的路由选择协议 一、路由选择协议ÿ…...

科研无人机平台P600进阶版,突破科研难题!
随着无人机技术日益成熟,无人机的应用领域不断扩大,对无人机研发的需求也在不断增加。然而,许多开发人员面临着无法从零开始构建无人机的时间和精力压力,同时也缺乏适合的软件平台来支持他们的开发工作。为了解决这个问题…...

Apache的简单介绍(LAMP架构+搭建Discuz论坛)
文章目录 1.Apache概述1.1什么是apache1.2 apache的功能及特性1.2.1功能1.2.2特性 1.3 MPM 工作模式1.3.1 prefork模式1.3.2 worker模式1.3.3 event模式 2.LAMP概述2.1 LAMP的组成2.2 LAMP各组件的主要作用2.3 LAMP的工作过程2.4CGI和FastCGI 3.搭建Discuz论坛所需4.编译安装Ap…...

CDL基础原理
一、CDL简介 CDL(全称Change Data Loader)是一个基于Kafka Connect框架的实时数据集成服务。 CDL服务能够从各种OLTP数据库中捕获数据库的Data Change事件,并推送到kafka,再由sink connector推送到大数据生态系统中。 CDL目前支…...

WPF基础入门-Class7-WPF-MVVN框架
WPF基础入门 Class7-MVVN框架 使用框架可以省掉如Class6中的ViewModelBase.cs的OnPropertyChanged,亦方便命令传参 1、NuGet安装CommunityToolkit.Mvvm(原Mircrosoft.Toolkit.Mvvm)也可以安装MVVMLight等其他集成库 2、显示页面࿱…...

C语言练习题第三弹!!!绝对典中典!!!
目录 1.单身狗1 1.1 题目 1.2 分析推理 1.3 代码实现 2.单身狗2 2.1 题目 2.2 分析推理 2.3 代码实现 3.字符串左旋 3.1 题目 3.2 分析推理 3.3 代码实现 3.3.1 方法一 3.3.2 优化一 3.3.2.1 思路分析 3.3.2.2 strcpy函数和strncat函数 3.3.2.3 代码实现 3.3.…...
Jedis
Jedis 使用Java操作redis Jedis是redis官方推荐的Java连接开发工具! 使用Java操作redis的中间件 测试 导入对应的依赖 <!-- https://mvnrepository.com/artifact/redis.clients/jedis --><dependency><groupId>redis.clients</groupId&g…...
Linux 使用TCP_INFO查询TCP连接的状态信息
Linux 上可以使用TCP_INFO查询TCP连接状态信息包括: 发送方拥塞窗口阈值、发送方缓冲区拥塞窗口、advmss(Advertised MSS)、通过 ACK 确认的累计字节数等等 struct tcp_info {__u8 tcpi_state;__u8 tcpi_ca_state;__u8 tcpi_retransmits;__…...

软件测试案例 | 气象探测库存管理系统的集成测试计划
将经过单元测试的模块按照设计要求连接起来,组成规定的软件系统的过程被称为“集成”。集成测试也被称为组装测试、联合测试、子系统测试或部件测试等,其主要用于检查各个软件单元之间的接口是否正确。集成测试同时也是单元测试的逻辑扩展,即…...
vue点击按钮重新加载页面(vue第一次加载页面点击按钮出现页面刷新问题之后一切正常)
问题描述 所开发的vue项目每次跑起来之后就会出现点击按钮后重新加载整个页面的问题,但是只会在第一次点击的时候出现,后面就不会在出现加载整个页面的情况。 原因 在form表单中使用button按钮导致form表单进行了页面刷新。button默认的“type‘submi…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...

深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...