实用指南:【Linux】深入理解Linux的进程(一)

news/2025/10/12 14:02:52/文章来源:https://www.cnblogs.com/ljbguanli/p/19136579

实用指南:【Linux】深入理解Linux的进程(一)

【Linux】深入理解Linux的进程(一)

学校OS书本讲的Linux的进程太哲学。本文将解释子进程,根据指令、代码、Linux内核源码剖析Linux的进程状态,包你听懂。

另外一提,本文命令都在云服务器上运行,先前我在WSL环境下进行测试,发现有部分指令和在传统Linux运行结果不同,比如孤儿进程的处理。(还是很坑人的这方面,所以我也推荐大家现在云服务器,或者本机虚拟机、物理机上进行学习)

冯诺依曼结构

在开始前,先讲解以下冯诺依曼的计算机结构,冯诺依曼结构十分伟大,走出了计算机进入家家户户的重要一步,另外冯诺依曼结构有助于理解CPU和内存、外设之间的关系,所以这里也会讲解一遍。

一个计算机是怎么接收数据然后进行处理、发送出去的呢?

外部信息先通过输入设备把数据传入到内存中,然后由CPU对数据进行解密、处理,再把数据加密后交给内存,内存把数据交给输出设备,输出设备把数据传到网络或者显示器等地方。

冯诺依曼结构十分厉害的一点就是把内存作为核心,都和内存打交道,而不是直接把信息交给CPU,内存成为CPU的一个缓冲区。

请添加图片描述

进程描述

学校讲的PCB完成进程描述功能,供CPU找到进程地址,进行进程调度,(我这里会重新讲,你不会也无所谓),本文将其具象化。

​ 在进入主题前,我们可以思考一下——如果对一个图书馆的书籍进行管理,应该怎么管理保障不会乱。

​ 我们可以赋予书籍不同的属性,比如:一本书可以按题材分类,也可以按主旨分类。然后把相同属性的书籍放在一起。放在计算机里,我们就需要用到struct对每本书的属性进行记录,然后在管理的时候,我们可以用到数据结构与算法的知识了。你可以顺序表,可以链表,可以哈希表,可以选择最适合完成业务需求的数据结构完成管理。

​ 上述步骤就是先描述(指创建结构体对属性进行记录的过程),再组织(将结构体封装到数据机构中,完成管理的过程)。

​ 事实上,你看到这里就已经掌握了计算机管理大部分东西的方法了。我们开始举例说明——你的计算机能够检测到你外设的状态,这就用到了先描述再组织,操作系统把不同的外设封装成不同的struct,然后进行管理。下文提到的进程也是如此。

PCB——task_struct

​ 我们看一下Linux的进程描述字段部分源码:

struct task_struct {
volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
void *stack;
atomic_t usage;
unsigned int flags;	/* per process flags, defined below */
unsigned int ptrace;
int lock_depth;		/* BKL lock depth */
struct list_head tasks;
struct plist_node pushable_tasks;
struct mm_struct *mm, *active_mm;
pid_t pid;
pid_t tgid;
struct list_head ptraced;
struct list_head ptrace_entry;
};

通过源码,我们可以知道所谓的PCB(进程属性描述字段)在Linux下就是task_struct,这个结构体描述了进程的所在文件位置、虚拟地址空间分配、文件打开的描述等等关键信息。注意struct list_head ptraced;,这个list_head本质就是封装了两个指针的结构体,而task_struct有很多list_head。他有什么用呢?

请添加图片描述

Linux的task_struct有很多个指针,这样可以把一个task_struct放在不同的数据结构、不同的链表、队列里了。而通过偏移量就可以准确找到想要找的元素位置——>&((task_struct*)0->link1)找到link1的偏移量。(struct task_struct*)((char*)next - x)找到下一个task_struct起始位置地址。这样,在不同数据结构下,都可以完美找到下一个/上一个进程描述字段在哪了。

加载到内存

我们写程序的过程,是向磁盘写内容的过程,那么怎么运行我们写的程序呢?结合冯诺依曼结构,CPU不能直接和磁盘打交道,所以你想要运行,需要先把你的进程放到内容中,这一过程我们叫做加载。

一个完整的进程 = task_struct + 自己的代码和数据。这个代码和数据就是在内存中。

Linux下一切皆文件,我们可以通过以下步骤深入理解代码加载到内存的过程

首先写一个死循环的程序,方便我们查看进程的状态,然后完成编译、链接、运行。(我这里编译链接生成myprocess文件)Linux操作系统给进程命名了一个id(我们把这个id叫做进程id,或者pid(process id)),并且生成这个id相同的文件夹放在/proc目录下,所以我们要先查看以下这个id是什么:我们新开一个会话,运行ps axj | head -1 ; ps axj | grep myprocess查看我们运行的程序信息,找到pid,这就是我们说的id。然后在/proc找相应的文件夹。详细操作如下:

请添加图片描述

可以在你的程序中通过chdir()系统调用修改cwd,这里就不演示了。

需要注意的内容

  • 那么怎么删除你刚刚运行的死循环的程序呢?你可以在刚刚运行的会话里输入ctrl c发送信号给进程,让他终止,kill -9 + pid也是一样的效果。不同的是,ctrl c只能给当前会话的在前台运行的进程发送终止信号,而kill -9可以给其他会话、后台的进程发送终止信号。信号部分会在后面详细讲。
  • /proc是内存级的,文件的属性和内容都放在内存,但是对于路径查找,还是走的文件系统那一套(文件系统会出详细解析的文章)。

子进程

子进程指在当前进程下创建的新进程,相应的,对于子进程,这个进程就是父进程。

fork

  • fork()命令可以创建进程,返回pid_t(long的宏定义),给父进程返回子进程的pid,给子进程返回0,如果创建进程失败会返回-1。
  • 子进程和父进程共享代码和数据,当子进程对数据进行修改,会发生写时拷贝。以方便节省内存空间,另一方面防止子父进程相互影响。(写时拷贝:指再内存上新开辟空间,同时完成页表映射的更新)
  • 那么问题来了
    • 为什么给父进程一个子进程pid,给子进程一个0,两个返回值不一样
      • 通过getppid()函数,子进程可以访问到父进程的pid,但是父进程不能通过函数查询到子进程的pid,如此返回值方便进行管理。
    • fork()创建子进程过程中完成了什么一系列操作?
      • 向操作系统申请新的task_struct空间
      • 父进程把自己task_struct原封不动copy给子进程
      • 把子进程task_struct放入runqueue
    • fork()为什么可以返回两次??
      • 完成创建子进程过程后,开始给return id;此时return id;会在父进程执行一遍,在子进程执行一遍,子进程还会发生写时拷贝,自然就可以返回两个值了。
    • 子父进程有什么关系?
      • 子进程共享父进程的代码和数据,当子进程对代码和数据有修改,会发生写时拷贝。
      • 子进程在结束时,会把return结果返回给父进程,tash_struct结构体也交给父进程回收。

进程状态

在此之前我们向讲三个系统调用,pid_t getpid()和pid_t getppid(),这两个系统调用分别是查看当前进程、父进程(父进程后文会讲)的进程id。先要查看运行的进程的进程状态还需要ps axj | head -1 ; ps axj | grep myprocess命令,你可以用while封装一下:while :; do ps axj | head -1; ps axj | grep myprocess; sleep 1; done就可以每过一秒查看一次myprocess进程的状态

使用ps axj指令查看Linux的进程状态有以下几种:(守护进程在网络通信部分讲,守护进程也是一种进程状态)

R(Running)

S(sleep可中断睡眠)

  • 可中断睡眠:阻塞导致的休眠,因为一个设备只能由一个进程使用,在此设备交给其他进程使用的时候,这个进程就会进入阻塞休眠的状态。除了这种情况,wait等待其他进程的信号也是S状态。
  • 内核上:我们上文提到过,Linux操作系统把不同设备封装成struct对象,那么,把需要这个设备的进程放到这个设备的struct结构体中,这就是阻塞。当设备空闲,要分配给其他进程时,从这个struct中寻找下一个分配的进程即可。

D(不可中断睡眠)

T

  • 暂停(因为ctrl z暂停)。
  • 可以通过jobs指令查看当前处于休眠的任务,同时会回显任务号。然后通过kill -9 %任务号指令就可以删除这个休眠的任务。也可以通过kill -SIGCONT %任务号让休眠进程继续进行。或者使用fg %任务号放在前台运行,使用bg %任务号放在后台运行。

t

Z(Zombel)

  • 僵尸状态:当子进程完成(或者被kill),子进程的PCB(tash_struct)此时没有父进程回收,就把此时的子进程状态称为僵尸状态。
  • 对于僵尸状态,如果你kill父进程,那么子进程终止的时候就会导致没有父进程回收task_struct,为了解决这一问题,操作系统会自动把你这个子进程的pid设为1,这个1其实就是bash的进程号。当你子进程运行完毕,task_struct就会交给bash回收,防止内存泄漏。

僵尸状态验证代码

#include <stdio.h>#include <unistd.h>#include <sys/types.h>int gval = 100;int main(){printf("父进程开始运行,pid: %d\n", getpid());pid_t id = fork();if (id < 0){perror("fork");return 1;}else if (id == 0){printf("我是一个子进程 !, 我的pid: %d, 我的父进程id: %d, gval: %d\n", getpid(), getppid(), gval);sleep(5);// childwhile (1){sleep(1);printf("子进程修改变量: %d->%d", gval, gval + 10);gval += 10; // 修改printf("我是一个子进程 !, 我的pid: %d, 我的父进程id: %d\n", getpid(), getppid());}}else{// fatherwhile (1){sleep(1);printf("我是一个父进程 !, 我的pid: %d, 我的父进程id: %d, gval: %d\n", getpid(), getppid(), gval);}}printf("进程开始运行,pid: %d\n", getpid());//  chdir("/home/whb");//  fopen("hello.txt", "a");//  while(1)//  {//      sleep(1);//      printf("我是一个进程 !, 我的pid: %d, 我的父进程id: %d\n", getpid(), getppid());//  }}

僵尸状态效果

请添加图片描述

X

  • 指结束的进程状态,通常情况下看不到,因为一进入X,PCB被回收,就瞬间查看不了此进程的状态。

想要验证R状态,只需要运行死循环while(1){}即可,想要验证S,只需要scanf()阻塞住即可。

一定要注意:验证R状态,万万不要涉及文件IO,涉及printf scanf之类的都不可以,IO会导致进程大多数时间处于S状态,你可能会看到S状态。

挂起状态

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

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

相关文章

2025年10月铝型材源头厂家最新推荐排行榜:五大优选企业深度解析!

在铝型材行业需求持续攀升的当下,采购决策正面临多重挑战:部分厂家产能有限导致订单交付延迟,原材料与工艺把控松懈造成产品精度不足,定制服务缺失难以匹配个性化需求,多层级供货推高采购成本。更值得关注的是,近…

2025外贸独立站推广最新权威推荐榜:高效引流与转化实战全解

2025外贸独立站推广最新权威推荐榜:高效引流与转化实战全解在全球数字化转型加速的背景下,外贸独立站已成为中国企业出海的核心阵地。根据最新行业数据显示,通过专业运营的独立站渠道,外贸企业平均获客成本比第三方…

软件工程第三次作业——结对作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class12Grade23ComputerScience这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class12Grade23ComputerScience/homework/13470这个作业的目标 完…

20232310 2025-2026-1 《网络与系统攻防技术》 实验一实验报告

一、实验目的 篡改程序流程——直接修改可执行文件,跳转至getShell; 栈溢出攻击——利用foo函数的缓冲区溢出漏洞,覆盖返回地址触发getShell; Shellcode注入——构造恶意输入注入自定义Shellcode并执行。 二、基础…

2025年CNC高压清洗机订做厂家权威推荐榜:技术实力与定制

2025年CNC高压清洗机订做厂家权威推荐榜:技术实力与定制在制造业智能化转型的浪潮中,CNC高压清洗机作为精密加工环节的关键设备,正发挥着不可替代的作用。这类设备不仅能有效清除CNC加工过程中产生的切削液、油污和…

K8s学习笔记(八) K8s资源对象 - 教程

K8s学习笔记(八) K8s资源对象 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monac…

小分子抗体药物:突破传统抗体瓶颈,在精准治疗中开辟新赛道

在治疗性抗体药物的大家族中,全长单克隆抗体(IgG,分子量约 150kDa)虽凭借高特异性、长半衰期占据主流,但面对实体瘤深层治疗、中枢神经系统疾病等复杂场景,其分子量大、组织穿透性差的问题逐渐凸显。而小分子抗体…

python nms

https://cloud.tencent.com/developer/article/2151436

2025年PE涂布机定做厂家权威推荐榜:技术实力与定制服务深

2025年PE涂布机定做厂家权威推荐榜:技术实力与定制服务深度解析在新能源、电子元器件、包装材料等行业高速发展的推动下,PE涂布机作为关键生产设备,其市场需求持续攀升。随着工艺要求的不断提高,企业对PE涂布机定做…

OI 笑传 #18

Septembersan今天是 ABC 427 的 DEF。 D 博弈,套路的设状态,令 \(dp_{i,k_1,k_2,op}\) 表示棋子在点 \(i\),Alice 还剩 \(k_1\) 步可以走,Bob 还剩 \(k_2\) 步可以走,现在拿棋子的是 \(op\),\(0\) 是 Alice,\(…

深入解析:开源的容器化平台:Docker

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

MiniExcel开源资料

MiniExcel开源资料MiniExcel开发文档

2025加药装置厂家权威推荐榜:精准计量与稳定运行优选指南

2025加药装置厂家权威推荐榜:精准计量与稳定运行优选指南在工业水处理、石油化工、电力能源等关键领域,加药装置作为流程工业中不可或缺的配套设备,其计量精度与运行稳定性直接影响生产效率和环保达标。随着2025年环…

Linux文本搜索工具grep命令使用

grep 是一个强大的文本搜索工具,广泛用于Unix和类Unix系统中,用于搜索包含指定模式的文本行。它由Ken Thompson编写,作为UNIX操作系统的一部分。其名称来源于ed命令 g/re/p(全局正则表达式打印)。以下是对 grep 命…

一款基于 .NET 开源免费、高效且用户友好文件搜索工具!

前言 无论是工作中的项目文档,还是学习中的研究资料,高效地管理和搜索这些文件成为了我们提升工作效率的关键。今天大姚给大家分享一款基于 .NET 开源免费(MIT license)、高效且用户友好的文件搜索工具,旨在帮助您…

2025上海保洁公司最新权威推荐榜:专业服务与用户口碑深度解

2025上海保洁公司最新权威推荐榜:专业服务与用户口碑深度解析在现代化都市运营体系中,专业保洁服务已成为企业高效运转和品质形象维护的重要保障。上海作为国际化大都市,保洁服务市场需求持续增长,服务品质参差不齐…

心得体会

不要美化你未走过的路

DedeCMS命令执行复现研究 | CVE-2025-6335 - 指南

DedeCMS命令执行复现&研究 | CVE-2025-6335 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&q…

2025视频拍摄厂家最新权威推荐榜:专业设备与创意方案首选

2025视频拍摄厂家最新权威推荐榜:专业设备与创意方案首选在数字化浪潮席卷各行各业的今天,视频内容已成为企业宣传、产品推广、品牌塑造的重要载体。随着5G技术的普及和人工智能的发展,视频拍摄行业正迎来前所未有的…

算法训练.16 - 实践

算法训练.16 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "C…