【Linux】僵尸进程|筛选输出|多进程与信号 学习笔记

news/2025/1/30 11:48:31/文章来源:https://www.cnblogs.com/advisedy/p/18694471

日期:2025.1.29(凌晨)

学习内容:

  • 僵尸进程
  • 筛选输出
  • 多进程与信号

个人总结:

僵尸进程:

首先我们需要先了解一件事情,我们在使用fork函数的时候可以使得当前的进程再创建出来一个子进程,这个子进程在大多数的时候会复制一份新的我们的内存地址,数据内存等。那么这个子进程所占有的资源如何释放呢?对于我们当前的进程占有的资源如何释放,我们显然知道,当return的时候,那么进程就应该结束了。但是子进程什么时候结束我们并不知道,所以这时候我们就需要一个可以帮助我们判断子进程是否结束的函数wait()函数。

  • wait函数:参数是一个指针,这个指针代表的意义是存储子进程的退出状态。这个退出状态具体怎么判断我们还需要宏,WIFEXITED,WEXITSTATUS,WTERMSIG。(宏的参数都是int)第一个是用来判断子进程退出状态是否正常,第二个是用来记录退出状态正常时的退出状态码,第三个是用来记录退出状态异常时的退出状态码(信号的编号)。
  • 退出状态正常:使用return或者exit函数退出,返回的值就是退出状态码
  • 退出状态异常:使用信号来中断进程,返回的值其实也就是信号的编号

这里还有一个小的前提是,当我们知道一个进程什么时候结束,那么就可以交由操作系统来回收在其所消耗的资源。

所以我们使用wait函数便可以回收。

一般会有两种情况,一种是父进程先结束,子进程再结束,第二种是子进程先结束,父进程再结束。

前者:当父进程提前结束时,子进程会被pid=1的进程托管,成为其新的父进程。进程名为init。而init自带wait函数,可以回收利用。

后者:由于子进程先结束,假设父进程此刻没有wait函数,那么我们不知道子进程结束的时机,数据内存无法释放,进程编号也无法回收被一直占用,这种情况,便是僵尸进程。

兜兜转转绕了一大圈,但是解决办法我们也已经说完啦,接下来直接上代码。

#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/wait.h>
using namespace std;int main()
{pid_t pid = fork();if (pid > 0) {// wait(nullptr);int *status=new int;wait(status);if (WIFEXITED(*status)) {cout << "GOOD" << " " << WEXITSTATUS(*status) << endl;return 0;}else {cout << "BAD" << " "<<WTERMSIG(*status) << endl;return -1;}}else if (pid == 0) {cout << "子进程结束" << endl;return 0;}else {cout << "fork error" << endl;return -1;}return 0;
}

当我们不在乎子进程的退出状态,可以直接传递一个空指针。

wait(nullptr);
cout << "FATHER END" << endl;

当然除了用wait函数,还有一个解法:使用signal(SIGCHLD,SIG_IGN);表示忽略子进程的信号,便会直接释放数据结构。和传递一个空指针没什么太大关系。

补充:

如果父进程还在运行,有一些子进程变成了僵尸进程,父进程结束之后,子进程依旧会被托管,然后释放。

筛选输出

(一个输出的命令) | grep xxx

这个指令依次解释:

|:代表将前面的命令变成后面命令的输入

grep:筛选作用,后面跟上一个名字xx,代表找寻含有xx的内容

所以找一个符合要求的进程,就可以使用

ps -ef | grep xxxx
  • ps 是一个用于显示当前系统上运行的进程状态的命令。
  • -e 选项表示显示所有进程。
  • -f 选项表示使用完整的格式显示进程信息。

多进程与信号

kill命令经常使用,但在c中可以使用kill函数向其他进程发送信号。

int kill(pid_t pid,int sig)

向pid进程发送sig信号:

  • 当pid>0时,便是指定那个pid的进程发送sig
  • 当pid=0时,便是向与目前进程属于同一个组的所有进程发送sig(包括当前进程本身)
  • 当pid=-1,则是向所有的进程发送信号

先上代码:

#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/wait.h>
using namespace std;void faExit(int sig)
{signal(SIGINT, SIG_IGN);signal(SIGTERM, SIG_IGN);cout << "父进程退出,id是" << sig << endl;kill(0, SIGTERM);exit(0);
}void chldExit(int sig)
{cout << "子进程" << getpid() << "退出,id是" << sig << endl;exit(0);
}
int main()
{for (int i = 1; i <= 64; i++) {signal(i, SIG_IGN);}signal(SIGINT, faExit);signal(SIGTERM, faExit);while (1) {pid_t pid = fork();if (pid > 0) {sleep(5);}else {signal(SIGTERM, chldExit);signal(SIGINT, SIG_IGN);while (1) {cout << "子进程" << getpid() << "在running..." << endl;sleep(2);}}}return 0;
}

代码中,父进程每一次都会创建一个新的父进程(也就是自己)和子进程,而子进程会进入最里面的while1循环,开始输出running。

在代码中,我们现将所有的sig都忽视了,防止别的命令对其产生影响。

然后我们使用kill函数遵循一个原则:杀死子进程可以直接杀,杀死父进程需要把子进程杀光,再杀自己。

我们假设用SIGTERM信号。

那么杀死父进程的操作,我们需要kill(0, SIGTERM); exit(0);,但是如果这样做了,我们同时也把自己杀了,没有保证先后序。所以我们要防止SIGTERM信号杀死自己,要在执行这一段之前先用SIG_IGN来忽视掉,就好了。

那么接下来处理杀死子进程的操作,我们只需要直接exit就好了。

此刻小tip:我们要在进入子进程的循环输出之前,先把信号的处理函数修改了,不然处理函数还会是父进程的处理函数。

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

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

相关文章

Quid faciam?

「先生、人生相談です。 この先どうなら楽ですか。 そんなの誰もわかりはしないよなんて言われますか。 ほら、苦しさなんて欲しいわけない。 何もしないで生きていたい。 青空だけが見たいのは我儘ですか。 」每到这种时候都感觉要撑不住了。 此时此刻眼眶就不禁为黏糊糊的透明…

【牛客训练记录】牛客2025年除夕娱乐赛

训练情况赛后反思 据说是临时准备的,今年好像没啥乐子题,除了两道猜猜题 A题 构造一个字符串使得 jiaran 子串至少出现 114514 次,直接输出 114514 次 jiaran点击查看代码 #include <bits/stdc++.h> // #define int long long #define endl \nusing namespace std;voi…

互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库控制舵机并多方法播放表情

前言 前面两篇文章讲了.NET IoT相关的知识点,以及硬件的GPIO的一些概念,还有点亮两个屏幕的方法,这些让大家对.NET的用途有了新的认识,那我们这回继续讲解.NET IoT的知识点,以及介绍一些好玩的东西,例如让视频通过机器人的屏幕播放起来,还有机器人的身体也能通过我们的代…

数据库物理备份:保障数据完整性和业务连续性的关键策略

title: 数据库物理备份:保障数据完整性和业务连续性的关键策略 date: 2025/1/29 updated: 2025/1/29 author: cmdragon excerpt: 在现代企业中,数据被视为最重要的资产之一。因此,确保数据的安全性、完整性和可用性是每个数据库管理员(DBA)的首要任务。在数据管理的过程…

《Operating System Concepts》阅读笔记:p1-p1

《Operating System Concepts》学习第 1 天,p1-p1 总结,总计 1 页。 一、技术总结 无。 二、英语总结(生词:1) 1.intermediary (1)intermediary: inter-("between, among") + medius("middle") c.intermediary originally referred to something or so…

【持续更新中】线段树全集

引入 一个数列,单点修改(加),区间查询(和)。 上述问题有很多种解法,如树状数组、分块、平衡树等,今天的主题是著名的线段树。 正题 (不确保按难度升序排序,自己看着目录调顺序吧) 线段树基本原理 因为需要区间查询,所以我们希望有一些捷径能将部分的数的和提前算好…

读量子霸权18读后总结与感想兼导读

《量子霸权》读书笔记,读薄率约23.48%,涵盖量子宇宙、量子计算机等读厚方向。笔记详细记录了各章节内容,亮点包括量子计算介绍、与传统计算机比较、与AI关系及平行宇宙探讨。1. 基本信息 量子霸权【美】加来道雄 著中信出版集团股份有限公司,2024年4月出版1.1. 读薄率 书籍总…

C# WinForm 自定义类型转换器重新编译后修改属性提示 InstanceDescriptor 错误的解决方案

当我们编写自定义的类型转换器比如从 TypeConverter、ExpandableObjectConverter 等继承,首次编译后,修改属性值是正常的,当再次编译后,再次修改属性则会提示如下错误: 属性“属性名”的代码生成失败。错误是: “类型转换器类名”无法将“属性名”转换为“System.Componen…

简单的javaweb

在这里我们可以看到springboots的基本结构 controller(控制器) 负责处理HTTP请求,调用相应的服务层方法,并返回视图或数据。 DailyReportController、InternalMessageController、PersonInfoController:这些是具体的控制器类,分别处理与日报、内部消息和个人信息相关的请…

AMD核显运行DeepseekR1-7b:使用mlc-llm框架,利用vulkan推理

任何支持vulkan的显卡都能跑! 本文使用的是Radeon890M核显,内存有多大就等于显存有多大。劲啊 1. 安装mlc-llm 官方文档 windows+vulkan: conda activate your-environment pip install --pre -U -f https://mlc.ai/wheels mlc-llm-nightly-cpu mlc-ai-nightly-cpulinux+vulk…