【Linux系统】进程控制

再次理解进程

进程:内核的相关管理数据结构(task_struct(进程控制块PCB),mm_struct(地址空间),页表) + 代码和数据

那么如何理解进程具有独立性

我们之前已经学习过进程控制块啊,地址空间啊,页表啊,他们不都是随着进程的创建而被创建,所以每个进程都有独立的一份这三个结构,那代码是共享的,数据是经过写时拷贝实现进程之间的独立的。

fork函数的返回

fork子进程返回0

fork父进程返回是子进程的pid

为什么父进程返回的是子进程的PID,给子进程返回的是0!!!

首先我们为了父进程方便对子进程进行标识,进而进行管理。

退出码?退出信号?

我们在写c/c++main函数的时候我们是不是往往都会写一个return 0来结束程序的运行!

为什么?

我们在命令行中使用echo $?内键命令

会发现打印出我们刚刚通过./运行的程序的main函数的返回值,我们把return后面设置为什么就会为我们返回什么!

我们知道,内键命令打印的都是bash内部的变量数据。

所以父进程bash获取到的是,最近一个子进程退出的退出码

告诉关心方(父进程),我任务完成的怎么样了!

实际上0代表成功,非0代表失败。

这是程序的退出码

1、2、3……不同的非零值,一方面表示失败,一方面表示失败的原因,

它们都有对应的错误描述,可以以字符串的形式打印出来!

父进程bash为什么要得到子进程的退出码呢?

这是要知道子进程的退出情况(成功,失败,失败的原因是什么?)

这些不都是为了让我们用户看到吗,为我们用户负责!!!

退出码不仅可以使用默认的,也可以进行自定义!

进程的终止

1.进程的终止在做什么?

释放曾经的代码和数据所占用的空间

释放内核数据结构(task_struct)-->我们知道子进程结束,父进程一直在跑但什么事情都不做,子进程进入Z(僵尸态),此时就是task_struct仍然存在的原因,这样就会造成内存泄露的问题。

那么进程的终止不就是回收资源,防止内存泄露吗!

2.进程终止的三种情况?

a.代码跑完,结果正确

可以通过进程的退出码决定!!!

b.代码跑完,结果不正确

同样可以通过进程的退出码决定!!!

c.代码执行时,出现了异常,提前退出了

两个原因,一个系统检测到错误,异常退出,一个我们人为自定义!0退出码

异常退出?(本质是因为进程收到了OS发给进程的信号!)

vs编程运行的时候,崩溃了 --- 操作系统发现你的进程做了不该做的事情,OS杀了进程,一旦出现异常,退出码没有意义了!!!

我为什么出现了异常?原因是?进程出异常,本质是因为进程收到了OS发给进程的信号!

我们可以写一段野指针的操作代码来观察现象

我们发现运行时是出现了段错误,OS提前终止进程。

当我们启动一个进程也可以用kill -11 pid来终止一个进程,其实这就是我们手动发给进程一个信号,让进程异常终止,报的也就是上面的段错误,所以进程出异常,本质是因为进程收到了OS发给进程的信号!

我们可以看进程退出的时候,退出信号是多少,就可以判断我的进程为什么异常了!!!

总结

所以我们面对程序出现错误,两步判断就可

  1. 先确认是否是异常
  2. 不是异常就一定是代码跑完了,看退出码就行。

最后,我们说衡量一个进程退出,我们只需要两个数字退出码,退出信号

这些都是要让父进程bash知道。

其实退出码,退出信号就是在我们的task_struct源代码中的两个个变量

inr exit_code,int exit_signal

3.如何终止?

a.main函数return表示进程终止(非main函数return,函数结束)

b.代码调用exit函数(注意:我们代码的任意位置调用exit,都表示进程退出)

c._exit() --- system call 系统调用接口

exit与_exit都可以让进程退出,那么它俩有什么区别呢?

exit vs _exit:exit会在进程退出的时候,充刷缓冲区,_exit不会,其实这是因为exit是c语言的库函数,它的底层还会调用_exit这个系统调用接口,来操作操作系统,所以充刷缓冲区应该在exit函数用户层的操作。

注意:目前我们说的缓冲区不是内核缓冲区!!!

4.进程等待?

是什么?

结论:任何子进程,在退出的情况下,一般必须要被父进程进行等待。进程在退出的时候,如果父进程不管不顾,退出进程,状态Z(僵尸态),造成内存泄漏。

为什么?

1.父进程通过等待,解决子进程退出的僵尸问题,,回收系统资源(一定要考虑的)

2.获取子进程的退出信息,知道子进程是因为什么原因退出的(可选的功能)

怎么办?

父进程可以通过调用wait/waitpid函数来做到上面两个事情

pid_t wait(int* status)

如果子进程没有退出,父进程其实一直在进行阻塞等待

参数部分,等待父进程中,等任意一个子进程退出。

返回值,等待成功时,子进程的pid。

进程阻塞等待?

子进程本身就是软件,父进程本质是在等待某种软件条件就绪,你如何理解阻塞等待子进程呢?

status是什么呢?

这里就要讲讲waitpid了

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,子进程存在且正常运行,则进程可能阻塞。
  • 如果不存在该子进程,则立即出错返回。
  • wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
  • 如果传递NULL,表示不关心子进程的退出状态信息。
  • 否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。
  • status不能简单的当作整形来看待,可以当作位图来看待。

所以status其实是个输出型参数,我们学过scanf函数,我们从键盘输入数据输出到一个变量中,status就类似把进程退出码与进程退出信号输出到status中,以便父进程拿到子进程的退出信息。

那status是如何存储进程退出码与进程退出信号两个数据呢?

其实status是使用了32位比特位来存储,用status的后7位来存储终止信号,第8位存储core dump(后面讲),再往后8位存储的是进程退出信息,再往后尚未使用。

 测试代码:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>void ChildRun()
{int *p = NULL;int cnt = 5;while(1){printf("I am child process, pid: %d, ppid:%d, cnt: %d\n", getpid(), getppid(), cnt);sleep(1);cnt--;*p = 100;}
}int main()
{printf("I am father, pid: %d, ppid:%d\n", getpid(), getppid());pid_t id = fork();if(id == 0){// childChildRun();printf("child quit ...\n");exit(123);}sleep(7);// father//pid_t rid = wait(NULL);int status = 0;pid_t rid = waitpid(id, &status, 0);if(rid > 0){printf("wait success, rid: %d\n", rid);}else{printf("wait failed !\n");}sleep(3);printf("father quit, status: %d, child quit code : %d, child quit signal: %d\n", status, (status>>8)&0xFF, status & 0x7F);
}

运行结果

这个就是因为段错误,出现异常,进程异常退出!

进程的非阻塞式等待方式代码

#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\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;
}

执行结果! 

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

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

相关文章

GitHub Actions 手动触发方式

目录 前言 Star Webhook 手动触发按钮 前言 GitHub Actions 是 Microsoft 收购 GitHub 后推荐的一款 CI/​CD 工具早期可能是处于初级开发阶段&#xff0c;它的功能非常原生&#xff0c;甚至没有直接提供一个手动触发按钮一般的触发方式为代码变动&#xff08;push 、pull…

【2024版】最新6款漏洞扫描工具来了!(附下载)看完这一篇就够了

目录 一、Nessus 二、AWVS 三、ZAP 四、w3af 五、北极熊 六、御剑 七、网络安全学习路线 &#xff08;2024最新整理&#xff09; 八、学习资料的推荐 1.视频教程 2.SRC技术文档&PDF书籍 3.大厂面试题 特别声明&#xff1a; 渗透测试收集信息完成后&#xf…

每日两题 / 104. 二叉树的最大深度 102. 二叉树的层序遍历(LeetCode热题100)

104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09; 递归判断&#xff0c;当前节点的最大深度为1 max(左节点的最大深度&#xff0c;右节点的最大深度) /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* …

Ansible---inventory 主机清单

一、inventory 主机清单 1.1、inventory介绍 hosts配置文件位置&#xff1a;/etc/ansible/hosts Inventory支持对主机进行分组&#xff0c;每个组内可以定义多个主机&#xff0c;每个主机都可以定义在任何一个或多个主机组内。 1.2、inventory中的变量 Inventory变量名含义…

八、VUE内置指令

一、初识VUE 二、再识VUE-MVVM 三、VUE数据代理 四、VUE事件处理 五、VUE计算属性 六、Vue监视属性 七、VUE过滤器 七、VUE内置指令 九、VUE组件 v-text 向其所在的节点中渲染文本内容。 (纯文本渲染)与插值语法的区别&#xff1a;v-text会替换掉节点中的内容&#xff0c;{{x…

springboot3项目练习详细步骤(第一部分:用户业务模块)

目录 环境准备 用户模块 注册 注册接口文档 ​编辑 实现结构 Spring Validation 登录 登录的接口文档 实现登录逻辑 JWT令牌 完善登录认证 拦截器 获取用户详细信息 接口文档 Usercontroller类中编写方法接口 忽略属性返回 优化代码ThreadLocal 更新用户基本信…

ubuntu启动修复(BIOS无法找到GRUB | 引导加载器)

Ubuntu启动修复&#xff08;无法找到GRUB|引导加载器&#xff09; 问题&#xff1a; 笔者的一台双系统主机&#xff0c;里面有两个硬盘&#xff0c;1T的硬盘装的是windows系统&#xff0c;2T硬盘装的是ubuntu20.04系统。因为长期使用ubuntu系统&#xff0c;所以选择格式化了1T…

Adobe Premiere Pro安装

一、安装包下载 链接&#xff1a;https://pan.baidu.com/s/1aYqTSQQutDguKYZE-yNHiw?pwd72l8 提取码&#xff1a;72l8 二、安装步骤 1.鼠标右击【Pr2024(64bit)】压缩包&#xff08;win11及以上系统需先点击“显示更多选项”&#xff09;【解压到 Pr2024(64bit)】。 2.打开…

【计算机毕设】小型企业办公自动化系统+vue - 免费源码(私信领取)

免费领取源码 &#xff5c; 项目完整可运行 &#xff5c; v&#xff1a;chengn7890 诚招源码校园代理&#xff01; 1. 研究目的 本项目旨在设计并实现一个小型企业办公自动化系统&#xff0c;利用Vue作为前端框架&#xff0c;为企业员工提供便捷的办公管理工具&#xff0c;提升…

mysql数据库调优篇章1

目录 1.认识数据库中日志的作用2.增加mysql数据库中my.ini 基本配置3.增加my.ini中参数配置4.查看已经执行过的sql语句过去执行时间5.找出慢查询的sql6. SHOW VARIABLES LIKE ‘innodb_read_io_threads’; SHOW VARIABLES LIKE ‘innodb_write_io_threads’; SHOW VARIABLES LI…

ArthasGC日志GCeasy详解

Arthas详解 Arthas是阿里巴巴在2018年9月开源的Java诊断工具,支持JDK6,采用命令行交互模式,可以方便定位和诊断线上程序运行问题.Arthas官方文档十分详细.详见:官方文档 Arthas使用场景 Arthas使用 # github下载arthas wget https://alibaba.github.io/arthas/arthas-boot.j…

了解tensorflow.js

1、浏览器中进行机器学习的优势 浏览器中进行机器学习&#xff0c;相对比与服务器端来讲&#xff0c;将拥有以下四大优势&#xff1a; 不需要安装软件或驱动&#xff08;打开浏览器即可使用&#xff09;&#xff1b;可以通过浏览器进行更加方便的人机交互&#xff1b;可以通过…

智慧手术室手麻系统源码,C#手术麻醉临床信息系统源码,符合三级甲等医院评审要求

手麻系统全套源码&#xff0c;C#手术麻醉系统源码&#xff0c;支持二次开发&#xff0c;授权后可商用。 手术麻醉临床信息系统功能符合三级甲等医院评审要求&#xff0c;实现与医院现有信息系统如HIS、LIS、PACS、EMR等系统全面对接&#xff0c;全面覆盖从患者入院&#xff0c;…

前端css中径向渐变(radial-gradient)的使用

前端css中径向渐变的使用 一、前言二、主要内容说明&#xff08;一&#xff09;、径向渐变的形状1.椭圆形渐变&#xff08;ellipse&#xff09;&#xff0c;源码12.源码1运行效果3.圆形渐变&#xff08;circle&#xff09;&#xff0c;源码24.源码2运行效果 &#xff08;二&…

C++青少年简明教程:C++程序结构

C青少年简明教程&#xff1a;C程序结构 一个简单的C程序源码如下&#xff1a; #include <iostream> using namespace std;int main() {cout << "Hello World" << endl;return 0; }下面解析一下。 1. #include <iostream> 这行代码的意思…

Python包管理工具

1、python包管理 在java开发生态&#xff0c;我们早已习惯使用maven或者gradle来构建和管理java项目。通过构建工具&#xff0c;我们可以非常方便对项目的依赖、打包、部署等进行管理&#xff0c;极大的减少手工操作的复杂性。 如果使用python开发生态&#xff0c;我们同样可…

k8s概述及核心组件

一、k8s概述 1.1 引言 docker compose 单机编排工具 有企业在用 docker swarm 能够在多台主机中构建一个docker集群 基本淘汰集群化管理处理工具 容器 微服务封装 dockerfile 编写成镜像 然后进行发布 dockerfile 可以写成shell脚本&#xff08;函数做调…

Kafka应用Demo:指派分区订阅消息消费

环境准备 Kafka环境搭建和生产者样例代码与《Kafka应用Demo&#xff1a;按主题订阅消费消息》相同。 消费者代码样例 public class KafkaConsumerService {private static final Logger LOGGER LoggerFactory.getLogger(KafkaConsumerService.class);private static final S…

【DFT】高 K/金属栅极阈值电压偏移的密度泛函模型

文章《Density functional model of threshold voltage shifts at High-K/Metal gates》&#xff0c;是由R. Cao、Z. Zhang、Y. Guo、J. Robertson等人撰写&#xff0c;发表在《Solid-State Electronics》期刊上。通过密度泛函理论&#xff08;Density Functional Theory, DFT&…

Redis(无中心化集群搭建)

文章目录 1.无中心化集群1.基本介绍2.集群说明 2.基本环境搭建1.部署规划&#xff08;6台服务器&#xff09;2.首先删除上次的rdb和aof文件&#xff08;对之前的三台服务器都操作&#xff09;1.首先分别登录命令行&#xff0c;关闭redis2.清除/root/下的rdb和aof文件3.把上次的…