初识Linux · 进程终止

news2024/9/30 19:23:46

目录

前言:

进程终止在干什么

进程终止的3种情况

进程如何终止


前言:

由上文的地址空间的学习,我们已经知道了进程不是单纯的等于PCB + 自己的代码和数据,进程实际上是等于PCB + mm_struct(地址空间) + 页表 + 自己的代码和数据。在地址空间那里我们结合写时拷贝重新理解了进程具有独立性,也理解了为什么fork函数会返回所谓的两个值,那么今天的话题是进程控制,我们拿fork举例,为什么fork返回给父进程的是子进程的pid,而子进程返回的值的0呢? 

这是因为子进程退出的时候,可以将自己的代码和数据退出了,但是自己的PCB还需要维护一段时间,因为父进程需要知道对应的退出信息,退出信息都是维护在PCB里面的,就像是A交给B办一件事,B干的怎么样,A总得知道吧?这个“干的怎么样”,就是B的退出信息。

那么对于进程终止这块内容,本文的介绍方式是:先想清楚进程终止是在干什么,然后理解进程终止的3种情况,最后理解进程如何终止。


进程终止在干什么

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include<sys/types.h>

int main()
{
	pid_t id = fork();
	if(id == 0)
	{
		printf("I am a child process,I will die\n");
	}
	else
	{
		sleep(10);
		printf("I am a father process,I wait\n");
	}

	return 0;
}

我们使用如上的代码,观察了一下僵尸进程的现象,子进程结束之后,父进程休眠10秒,这个过程,子进程已经结束了,但是父进程没有回收它,所以子进程短暂的变成了僵尸进程。

这里提问,进程创建的时候,是自己的代码和数据先过去还是PCB那些数据结构先过去呢?

结合上大学的时候,是你的数据先过去还是人先过去来思考哦~ 

那么当你毕业了,你的数据是否瞬间就没有了呢?你的人当然是先走了,但是数据总得维护一段时间吧?进程这里同理,当进程终止的时候,进程的代码和数据所占据的空间是被释放了,但是,进程的PCB是需要被维护一段时间的,因为要记录退出信息,此时有一个对应的状态就是zombie,即僵尸进程。

所以进程终止的时候,第一个要干的事就是对应的代码和数据占据的空间先释放掉,然后是进程对应的PCB被维护起来,整个进程的状态变成僵尸,等待回收,对应的退出信息记录在PCB里面,此时进程终止的操作也就完成了,剩下的是等待父进程来回收即可。


进程终止的3种情况

进程终止的3种情况,分别是代码正常,结果正确,代码不正常,结果不正确,以及代码执行的时候,出现了异常,提前退出了,这是3种情况,介绍的时候即围绕这三种情况进行讲解。

思考一个问题:为什么C语言阶段我们写main函数默认要返回的是0呢?为什么不是1?不是100呢?

int main()
{

	return 1;
}
int main()
{

	return 0;
}
int main()
{

	return 100;
}

这三种代码我们放在VS跑都是没有问题的,那么是不是代表main函数的返回值我们可以随便返回呢?

当然不是,在C语言阶段我们只是在语言层面知道了可以返回值而已,但是返回给的谁的我们是不知道的。在Linux阶段,我们通过了解退出码这个知识点,就会知道main的返回值怎么回事。

相信大部分人都知道error,错误码,当我们程序报错的时候,会返回错误码,我们可以打印出来看看:

#include<string.h>

int main()
{
	for(int errcode = 0; errcode <= 255; errcode++)
 	{
       	printf("%d: %s\n", errcode, strerror(errcode));
	}
	return 0;
}

从133开始,就没有错误码了,所以是unknown,那么第一个错误码,也就是0,表示的意思是success,也就是成功,程序成功运行的时候并且结果正确,返回的错误码是0,也就代表了成功。

现在是知道了错误码,那么我们可以通过命令echo $? 来看到对应的错误码:

看这个2,是不是很熟悉?就是我们刚才的No such file or directory,对于错误码,系统有自己的一套规范,但是错误码是可以自己自定义的,也就是说,我们可以拥有自己的一套错误码的体系:

比如:

int main()
{
        for(int errcode = 0; errcode <= 255; errcode++)
        {
        printf("%d: %s\n", errcode, strerror(errcode));
        }
        return 100;
}

我们自己规定返回的是100,那么退出码就是100,因为echo是内建命令,直接获取到的父进程的资源,那么bash创建的子进程main,再获取到了退出码为100,这就是退出码

退出码唯一的一个稍微规范的是0为success,!0为失败,但是失败的具体原因是我们自己规定的,而不是错误码那样,系统已经规定好了。

但是echo $?只能获取最近的一个进程的退出码:

得到结论:退出码可以默认,也可以自定义

进程如果正常运行,结果是否正确,都只需要一个退出码即可,父进程就可以知道这个进程的情况是什么样的。

进程如果是异常终止的呢?

比如我们写了一个死循环,进程自己停下来不了,我们使用kill发送9号信息码,进程被杀死,就会:

此时,我们看到对应的错误码是137,可是错误码还有意义吗?实际上没有,因为进程异常终止的本质,就是OS给了进程信号,比如:

int main()
{
        int* p = NULL;
        *p = 0;
        return 0;
}

这段代码是一定会报错的:

此时报错,

专业点讲叫做段错误

本质上就是发生了异常,此时进程收到了OS给的信号,并终止:

kill11号命令,SIGSEGV,就是上面的缩写:

int main()
{
        while(1)
        {
                printf("Hello Linux,pid is %d\n",getpid());
                sleep(1);
        }
        return 0;
}

此时我们使用11号信号终止进程,就会报段错误,实际上就是进程收到了OS的信号。

也就是说,如果进程异常终止了,退出码是没有用的,退出码只有在程序正常运行的时候有用,进程如果是异常终止,我们想要知道进程为什么异常,就应该查看信号码了,怎么查看,我们在进程等待章节提及。

源码中,进程退出的时候,对于exit_code exit_signal就需要维护,即对应上面的三种情况。 


进程如何终止

进程如何终止的呢?难道是程序运行结束就终止了吗?

不完全是,如果程序是:


int main()
{

	return 0;
}

如果是main函数运行到了return 0 ,此时进程代表终止,但是如果是其他函数碰到了return 0,只能说是函数结束,这是第一种情况。

进程终止的第二种情况是exit,我们可以使用两个函数,exit _exit:

int main()
{
   printf("hello 111\n"); 
   sleep(2);

   //_exit(3);
}

这段代码和缓冲区有关,大家应该知道怎么回事,今天我们这样写:

int main()
{
   printf("hello 111"); 
   sleep(2);

   exit(3);
}

可以看到对应的退出码是3,和return效果好像是一样的,因为进程终止,所以会强制刷新缓冲区,即不是先打印,是先休眠的。

此时我们使用系统接口_exit,刚才的exit我们在C语言阶段就使用过,这是库函数,使用_exit呢?

欸?运行了之后为什么什么也没有?

可是对应的退出码也有。

这里,第一个点是exit _exit运行到了都会直接进程终止,并且退出码是exit _exit里面的num,第二点,缓冲区的刷新,_exit调用了没有打印,代表缓冲区没有刷新,我们之前有一个图:

C库函数在系统调用的上方,系统调用在OS的上面,也就是说,exit刷新的缓冲区一定不在OS里面,因为它没有权限,_exit才有资格接触OS,这就说明刷新的缓冲区是在C库函数的上面,得出结论,目前我们说的缓冲区,并不是内核缓冲区!

这是两种进程终止所引发的缓冲区的一个知识点,进程终止我们可以使用return 也可以使用exit,也可以使用_exit,区别就是缓冲区的刷新,但是对于PCB里面的exit_code exit_signal都是要维护的,无非就是缓冲区的刷新而已。

进程终止的更多小点会放在进程等待,即下篇文章哦~


感谢阅读!

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

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

相关文章

LLM 构建Data Multi-Agents 赋能数据分析平台的实践之⑥:NL2SQL技术探讨

一、概述 NL2SQL&#xff08;Natural Language to SQL&#xff09;是一种将自然语言转换为结构化查询语言的技术。它可以帮助用户通过使用自然语言来与数据库进行交互&#xff0c;而无需了解复杂的SQL语法。 NL2SQL技术的背景&#xff1a; 随着人工智能的发展&#xff0c;越…

prometheus + alertmanager + PrometheusAlert实现告警

prometheus 收集监控数据 alertmanager 制定告警路由 PrometheusAlert 连通告警webhook 一、prometheus配置 https://prometheus.io/download/ 1.1、prometheus安装 包的下载直接wget就行,放在data目录下,解压后在prometheus目录下创建config和rule目录 配置了热重启&#…

聊一聊 C#中有趣的 SourceGenerator生成器

一&#xff1a;背景 1. 讲故事 前些天在看 AOT的时候关注了下 源生成器&#xff0c;挺有意思的一个东西&#xff0c;今天写一篇文章简单的分享下。 二&#xff1a;源生成器探究之旅 1. 源生成器是什么 简单来说&#xff0c;源生成器是Roslyn编译器给程序员开的一道口子&am…

vxe-grid给单元格加上触发事件

效果&#xff1a;输入框的双击事件(其他事件可以由此替换) 代码 // gridTableOptions是每列的配置项 <vxe-grid v-bind"gridTableOptions" :data"goodsList" ref"xTable">// edit_spbh 是对应的样式名&#xff0c;是写在gridTableOption…

如何通过日志快速定位TTS的缓存放音文件(mod_cti基于FreeSWITCH)

文章目录 前言联系我们分析过程1. 测试话术&#xff0c;记录日志2. 关键词搜索 前言 顶顶通呼叫中心中间件在运行话术时&#xff0c;如果有通过TTS合成的语音&#xff0c;会被freeswitch缓存在目录中&#xff1a;/ddt/fs/storage/http_file_cache。 我们可以分析freeswitch日志…

学习Webpack中图片-JS-Vue-plugin

目录 图片文件资源模块类型 JS文件babel命令行使用babel-loaderbabel-preset Vue文件vue-loadervue/compiler-sfc pluginCleanWebpackPluginHtmlWebpackPluginDefinePlugin 图片文件 需要先在项目中使用图片&#xff0c;比较常见的使用图片的方式是两种&#xff1a; img元素&…

LeetCode 918. 环形子数组的最大和

原题链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 给定一个长度为 n 的环形整数数组 nums &#xff0c;返回 nums 的非空 子数组 的最大可能和 。 环形数组 意味着数组的末端将会与开头相连呈环状。形式上&#xff0c; nums[i] 的下一个元素是 nums[(i 1) % n…

基于STM32的智能室内空气质量监控系统

目录 引言项目背景环境准备 硬件准备软件安装与配置系统设计 系统架构关键技术代码示例 传感器数据采集与处理空气质量分析与报警显示与数据记录功能应用场景结论 1. 引言 智能室内空气质量监控系统用于实时监测环境中的空气质量&#xff0c;通过检测空气中的CO2、PM2.5、温…

软件测试学习笔记丨Pytest 学习指南

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/32336 基本介绍 pytest框架是一个成熟&#xff0c;全面的测试框架&#xff0c;具有非常丰富的第三方插件&#xff0c;并且可以自定义扩展 比如&#xff1a;pytest-selenium , pytest-html ,…

Git常用方法——详解

一、下载安装git git官网&#xff1a; Git - Downloads (git-scm.com) 下载安装Git&#xff08;超详细超简单&#xff09;_git下载-CSDN博客 二、克隆下载至本地 1、复制HTTPS链接 在gitee或者gitLab或者gitHub上复制HTTPS链接 2、打开Open Git Bash here 在本地想要新建文…

小程序原生-列表渲染

1. 列表渲染的基础用法 <!--渲染数组列表--> <view wx:for"{{numList}}" wx:key"*this" > 序号&#xff1a;{{index}} - 元素&#xff1a;{{item}}</view> <!--渲染对象属性--> <view wx:for"{{userInfo}}" wx:key&q…

怎么给视频加片头片尾和字幕

在这个视觉内容爆炸的时代&#xff0c;一段精心制作的视频不仅能吸引眼球&#xff0c;更能传达深刻的情感与信息。而一个引人入胜的片头、一个温馨感人的片尾&#xff0c;以及恰到好处的字幕&#xff0c;无疑是提升视频质感的关键。那么新人要怎么给视频加片头片尾和字幕效果呢…

2024年9月收评

金1是从2005年12月开始&#xff0c;到现在2024年5月&#xff0c;还差7个月整整20年。一共11轮。 这20年里&#xff0c;真正形成单边趋势&#xff0c;能较好获利或者说至少不亏损的一共有以下几次&#xff0c; 第1轮&#xff0c;第2轮&#xff0c;第7轮&#xff0c;第8轮&…

《程序猿之Redis缓存实战 · 集合类型》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

基于微信小程序的商品展示+ssm论文ppt源码调试讲解

2 系统开发环境 2.1微信开发者工具 微信开发者工具现在已经被小程序开发团队开发运行&#xff0c;目前微信开发者工具任然在不断的完善中&#xff0c;在开发小程序时经常要不断的更新。可以使用微信扫码登陆开发者工具&#xff0c;开发者工具将使用这个微信帐号的信息进行小程…

为VRoidStudio制作的vrm格式模型制作blendshape

零、效果展示 bs视频演示 一、准备相关插件 1、VRoidStudio&#xff08;免费&#xff09; 下载网址&#xff1a;https://vroid.com/en/studio 2、UniVRM&#xff08;免费&#xff09; 下载网址&#xff1a;https://github.com/vrm-c/UniVRM/releases 注意&#xff1a;unity…

Qt --- 常用控件的介绍---Widget属性介绍

一、控件概述 编程&#xff0c;讲究的是站在巨人的肩膀上&#xff0c;而不是从头发明轮子。一个图形化界面上的内容&#xff0c;不需要咱们全都从零区实现&#xff0c;Qt中已经提供了很多内置的控件了&#xff08;按钮&#xff0c;文本框&#xff0c;单选按钮&#xff0c;复选…

yolov8实例分割重要图片

训练分割要准备好数据集和分割预训练权重文件 下面这张图是数据集的格式 下面这张图配置数据集&#xff0c;下面names 要和labelme转txt里配置的一样 下面这张图进行训练&#xff0c;配置一些全局参数 &#xff0c;初始的yolov8s-seg.pt文件需要到github上yolov8开源项目里下 l…

linux部署redis,整合ansible和redis

准备服务器192.168.45.133&#xff0c;192.168.45.135 在135上执行命令yum install -y redis安装redis yum install -y redis 源码安装方法 wget http://download.redis.io/releases/redis-2.8.13.tar.gz tar zxf redis-2.8.13.tar.gz cd redis-2.8.13 make PREFIX/usr/loca…

Cannon-es.js之Distance Constrait模拟布料

本文目录 前言1、Particle2、前置代码准备2.1 代码2.2 效果 3、使用距离约束模拟布料3.1 代码3.2 效果 前言 在现代Web开发中&#xff0c;实现逼真的物理效果对于提升用户体验至关重要。Cannon-es.js&#xff0c;作为Cannon.js的ES6模块版本&#xff0c;凭借其轻量级、高性能和…