【Linux 学习计划】-- 进程概念与本质 | pid & ppid | 进程创建与多进程(fork)

目录

进程是什么?

[代码和数据 与 PCB 在系统上的联动](#代码和数据 与 PCB 在系统上的联动)

[pid & ppid](#pid & ppid)

创建子进程

结语


进程是什么?

我们可以打开Windows中的任务管理器:

我们可以在上面看到,所有正在跑的程序都会在上面显示,这其实就都是一个个的进程

那么进程具体是什么?

首先,我们的代码如果要跑起来的话,就需要先加载到内存中,这是冯诺依曼体系结构规定的

那么当我们将数据和代码 加载到内存之后,这些数据和代码是否就是进程呢?

试想一下,你如何说你是一个学校的学生?因为你人在学校你就是了吗?那保安大叔也在学校里啊?你放假回家了就不是那个学校的学生了吗?显然不是,你是那个学校的学生,是因为你的信息在学校的教务系统里面被管理着

对于操作系统而言,我们光有代码和数据还不够,还需要将其管理起来,也就是:先描述,再组织

我们需要先用struct把进程给描述起来,接着就是将这一个个的struct用特定的数据结构管理起来

接着,我们对进程的管理,就转换成了对特定数据结构的管理

而我们用来描述进程的struct,就是PCB,也就是process control block(进程控制块)

但是PCB,是一个总称,而在Linux中则是task_struct,这就好比"奔驰"和"汽车",奔驰只是汽车中的一种,仅此而已

所以我们就可以得出结论了,也就是:

进程 = PCB + 代码和数据

看这张图,代码和数据加载到内存中,然后task_struct中有内存指针可以指向这部分对应的代码和数据,接着CPU就对task_struct进行管理

以上就是进程的概念了,讲完了概念,我们来演示一遍代码和数据在系统中具体是怎么和PCB联动起来的

代码和数据 与 PCB 在系统上的联动

如上图,我们的代码数据是加载到了内存中的用户空间,而我们的PCB则是在内存中的内核空间中存着

这时有新的代码和数据进来内存了,我们就在内核空间中new一块空间出来,然后PCB中的内存指针指向对应的代码和数据,这样就能将这部分内容管理起来了

接着,我们系统中不断有进程需要创建,所以task_struct就不断变多

这些task_struct就全部链接起来(数据结构),这时候就将进程管理起来了

而后面如果涉及到进程调度,等待之类的,就都让CPU和内核处理了

pid & ppid

我们在Linux敲指令时,当我们想跑程序了,都会用 ./XXX 跑代码,而这个指令的本质就是运行进程

包括我们敲的ls、pwd、cd等等指令,都是启动了进程,只不过这些进程的开始到结束都比较快

而一个进程的属性中,必然会有自己的id,也就是pid,而每一个pid都是唯一的

如果我们想知道pid的话,我们有两个办法

第一个就是用指令:

  1. ps ajx | head -1 && ps ajx | grep name

  2. ls /proc/

ps指令查我们具体某一个进程比较好,因为grep就是筛选用的

但如果想用代码查呢?

首先我们需要知道的是,只要你想知道pid,那么就一定只能在PCB中找

但是,PCB是被内核数据结构管理的,而我们用户是无法直接进内核查东西的,我们只能使用系统接口

而这时我们就有了一个系统接口:getpid()

这个pid是哪个进程的pid呢?我们程序跑起来的时候就已经是一个进程了,所以就是那个跑起来的进程,而我们的进程最后结束了,所以就没法在外面用指令查到

同时,我们除了pid之外,还有一个ppid,第一个p就是parent的意思,也就是父进程

这也就意味着,我们每一个进程都是由另一个进程创建出来的,但是每一个进程之间互相不影响

那我们这个程序自始至终都没有看到父进程的影子,那我们的父进程会是谁呢?

我们先将父进程的id打印出来,接着我们再用ps命令进行查找,最后用grep命令最筛选:

我们可以看到,启动我们程序的父进程就是bash,也就是我们的命令行解释器

创建子进程

同样的,创建子进程我们也是需要调用系统接口------fork

先来简单用一用,来看这样一段代码:

我们会看到,222居然被打印了两次,这是因为我们我们在fork之后,就已经有两个进程了,而两个进程之间是互相独立的

也就是说,fork之后,分了两个进程,一个打印了第一个222,一个打印了第二个222

那我们怎么看到是否真的有两个进程呢?还是原来那个代码,只不过我们将其改成不断循环打印,如下:

确实我们可以看到,在test运行的时候有两个进程,上面的是父进程,因为下面那个进程的ppid是他的pid

接下来我们就需要来好好讲讲fork这个函数了:

首先,我们的fork是有两个返回值的,创建完进程之后,如果创建成功,就将子进程的pid作为返回值返回给父进程,然后将 0 返回给子进程

如果没有成功创建子进程,那么fork就会将 -1 返回给父进程

听起来似乎很诡异,因为我们之前从来没有说一个函数返回两个返回值的情况,但是先不管那么多,我们先来写一个代码验证一下

顺便一提,我们为什么要有子进程呢?这是因为我们需要子进程帮我们处理不同的任务,这点我们目前暂时没处理过什么任务暂时无法理解,记着就行

现在来解释fork,为什么能返回两个参数呢?这是因为我们在fork返回也就是return的时候,我们前面的业务就已经做完了,也就是,进程已经创建出来了

那么我们的进程只需要用一下条件判断,就能知道哪个进程要返回哪个了

结语

这篇文章到这里就结束啦!!~( ̄▽ ̄)~*

如果觉得对你有帮助的,可以多多关注一下喔

相关推荐
西岸行者4 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意4 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J5 天前
从“Hello World“ 开始 C++
c语言·c++·学习