【Linux】—— 进程的基本概念、PCB、fork

🌏博客主页:PH_modest的博客主页
🚩当前专栏:Linux跬步积累
💌其他专栏:
🔴 每日一题
🟡 C++跬步积累
🟢 C语言跬步积累
🌈座右铭:广积粮,缓称王!

基本概念

课本概念: 进程的一个执行实例,正在执行的程序等。
内核观点: 担当分配系统资源(CPU时间,内存)的实体。

当你的代码进行编译链接之后便会生成一个可执行程序,这个可执行程序本质上是一个文件(例如:main.cpp),是放在磁盘上的。当我们运行这个可执行程序时,本质上是将这个程序加载到内存后,CPU才能对其进行逐行的语句执行,当这个程序加载到内存后,我们就不应该将它叫做程序了,而应该称其为进程

在这里插入图片描述

在这里插入图片描述

描述进程-PCB

  • 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
  • 课本上称之为PCB,Linux操作系统下的PCB是:task_struck

我们可以使用 ps aux 来显示系统中存在的进程:
在这里插入图片描述
开机的时候启动的第一个程序就是我们的操作系统(操作系统是第一个加载到内存的),操作系统主要是做管理工作的,其中包括对进程的管理。

操作系统如何对进程进行管理呢?
首先双手奉上六字口诀:先描述,再组织。当一个进程出现时,操作系统会对其进行描述,之后对该进程的管理就转化为对其描述信息的管理。
进程信息被放在一个叫做进程控制块(PCB)的数据结构中,可以理解为进程属性的集合。

struct PCB
{
	//状态相关的代码(一般是一个整形变量,不同的数字表示不同的状态)
	//优先级相关的代码
	//内存指针字段
	//... 包含进程几乎所有的属性字段
	struct PCB* next;
}

在这里插入图片描述

小结:

  • 当磁盘内的可执行程序加载到内存时,内存会生成对应的PCB对其代码和数据进行管理。未来,所有对进程的控制和操作,都只和进程有关,和进程的可执行程序没有关系!
  • 对进程的管理转化为对PCB对象的管理,而PCB对象是以链表形式连接起来的,又转化为对链表的增删查改。
  • 因此,不难得出进程的组成:
    进程 = 内核PCB对象 + 可执行程序
    或者:
    进程 = 内核数据结构 + 可执行程序

task_stuct - PCB的一种

进程控制块(PCB)是描述进程的,在C++中我们称之为面向对象,在C语言中我们称之为结构体,而Linux是用C语言写的,那么Linux中的进程控制块必定是用结构体来实现的。

  • 在Linux中描述进程的结构体叫做 task_struct。
  • task_struct 是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。

task_struct内容分类

  • 标示符: 描述本进程的唯一标示符,用来区别其他进程。
  • 状态: 任务状态,退出代码,退出信号等。
  • 优先级: 相对于其他进程的优先级。
  • 程序计数器(pc指针/eip): 程序中即将被执行的下一条指令的地址。
  • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
  • 上下文数据: 进程执行时处理器的寄存器中的数据。
  • I/O状态信息: 包括显示I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
  • 记账信息: 可能包括处理器时间总和,使用的时钟总和,时间限制,记账号等。
  • 其他信息。

补充:pc指针

  • pc指针指向哪一个进程的代码,就表示哪一个进程被调度运行!
  • 判断、循环、函数跳转的本质:修改pc指针。

组织进程

可以在内核源代码里找到它。所有运行在系统里的进程都以 task_struct 链表形式存在内核里。

查看进程

通过系统目录查看

在根目录下有一个名为proc的系统文件夹
在这里插入图片描述
文件夹当中包含大量进程信息,其中有些子目录的目录名位数字。
在这里插入图片描述
这些数字其实是某一些进程的PID,对应文件夹当中记录着对应进程的各种信息。我们若想查看PID为1的进程的进程信息,则直接查看该文件夹即可。
在这里插入图片描述

通过ps命令查看

单独使用ps命令,会显示所有进程信息。
在这里插入图片描述
ps命令与grep命令搭配使用,即可只显示某一进程的信息。
在这里插入图片描述

通过系统调用获取进程的PID和PPID

通过使用系统调用函数,getpid 和 getppid 即可分别获取进程的 PID 和 PPID。
示例:
在这里插入图片描述
当运行该代码生成的可执行程序后,便可循环打印该进程的PID和PPID。
在这里插入图片描述
我们可以通过ps命令查看该进程的信息,即可发现通过ps命令得到的进程的PID和PPID与使用系统调用函数getpid和getppid所获取的值相同。

通过系统调用创建进程 - fork初始

fork函数创建子进程

fork是一个系统调用级别的函数,其功能就是创建一个子进程。
例如:
在这里插入图片描述
若是代码当中没用fork函数,我们都知道代码的运行结果就是循环打印该进程的PID和PPID。而加入了fork函数后,代码运行结果如下:
在这里插入图片描述
运行结果是循环打印两行数据,第一行数据是该进程的PID和PPID,第二行数据是代码中fork函数创建的子进程的PID和PPID。我们可以发现fork函数创建的进程的PPID就是proc进程的PID,也就是说proc进程与fork函数创建的进程之间是父子关系。

每出现一个进程,操作系统就会为其创建PCB,fork函数创建的进程也不例外。
在这里插入图片描述
我们知道加载到内存当中的代码和数据是属于父进程的,那么fork函数创建的子进程的代码和数据又从何而来呢?
在这里插入图片描述
运行结果:
在这里插入图片描述
实际上,使用fork函数创建子进程,在fork函数被调用之前的代码被父进程执行,而fork函数之后的代码,则默认情况下父子进程都可以执行。需要注意的是,父子进程虽然代码共享,但是父子进程的数据各自开辟空间(采用写时拷贝)。

注意点: fork函数创建子进程之后就有了两个进程,这两个进程被操作系统调度的顺序是不确定的,这主要取决操作系统调度算法的具体实现。

使用if进行分流

一般情况我们不会直接让父子进程做相同的事情,通常情况会使用if进行分流,让父进程和子进程做不同的事情。

fork函数的返回值:

  1. 如果子进程创建成功,在父进程中返回子进程的PID,而在子进程中返回0。
  2. 如果子进程创建失败,则在父进程中返回-1。
    在这里插入图片描述
    fork创建出子进程后,子进程会进入到if语句的循环打印中,而父进程会进入到else if语句的循环打印当中。
    在这里插入图片描述

相关推荐

  1. Linux进程基本概念

    2024-07-21 06:14:01       28 阅读
  2. Linux进程基本概念

    2024-07-21 06:14:01       22 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-21 06:14:01       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-21 06:14:01       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-21 06:14:01       45 阅读
  4. Python语言-面向对象

    2024-07-21 06:14:01       55 阅读

热门阅读

  1. Perl文件系统过滤:数据筛选的艺术

    2024-07-21 06:14:01       20 阅读
  2. 【音视频】AAC编码器与ffmpeg生成AAC数据

    2024-07-21 06:14:01       16 阅读
  3. 求职学习day7

    2024-07-21 06:14:01       18 阅读
  4. 算法学习2——排序算法(2)

    2024-07-21 06:14:01       15 阅读
  5. Jupyter Notebook与机器学习:使用Scikit-Learn构建模型

    2024-07-21 06:14:01       18 阅读
  6. C#面:ASP.NET Core项目如何设置IP地址和端口号

    2024-07-21 06:14:01       13 阅读
  7. 有关css的题目

    2024-07-21 06:14:01       15 阅读
  8. Go: IM系统接入ws进行消息发送以及群聊功能 (5)

    2024-07-21 06:14:01       14 阅读