Linux--进程概念(1)

本文介绍了操作系统的基本概念及其管理软硬件资源的重要性,阐述了冯·诺依曼体系结构,强调了CPU与存储器在计算机运行中的角色。深入探讨了进程管理和PCB(进程控制块)的作用,明确了进程与程序的区别,并通过实例说明了如何查看及创建进程。上下文数据的产生和处理机制也得以解析,包括时间片轮转和上下文切换确保多进程并发的假象。
摘要由CSDN通过智能技术生成

1. 操作系统

  • 是什么

操作系统(Operator System,简称os)是一款专门针对软硬件资源进行管理工作的软件

  • 为什么

通过对软硬件的正确管理,才能有稳定的系统。通过对用户提供良好的运行环境,才能满足需求,这便是操作系统出现的原因。

2. 冯·诺依曼体系结构

计算机中,CPU并不直接和外设打交道,外设指的是外部设备:输入设备、输出设备等。原因是CPU的运行速度比外设快多了,不是一个层次的元件。所以就有了存储器;存储器的作用就是接收输入进来的数据,将这些数据交到CPU进行处理,然后CPU再输出给存储器,这是CPU与存储器的交互行为。例如,我们在编程的时候是计算机的内存先得到我们的代码(通过输入设备),然后才是CPU(通过存储器)。

在这里插入图片描述

3. 如何理解“管理”

管理的理念:先描述,再组织

对于计算机来说,要正常运行就需要各方互相协作,既然是协作就必须要有一个统一的领导者,这个领导者便是操作系统。操作系统起到承上启下的作用,对上为用户提供良好的运行环境(比如银行的工作窗口),对下管理好软硬件资源。

操作系统通过结构体(PCB)对进程进行描述,再进行组织(通过数据结构,链表等),就可以实现对进程的管理。

下文中将会有具体的图解,对这段话进行解释。

3. 描述进程–PCB

3.1 为什么要有PCB

既然操作系统要对进程进行管理,那么就应当要有一个角色来实现这个管理的过程。这个角色就是PCB(process control block)。

在操作系统层面,PCB是一个进程控制块在类型层面它是一个结构体类型

  • 要点
  1. 在Linux系统中,PCB的表示方法为:struct task_struct{ //进程所有的属性}。
  2. PCB是在操作系统上的一个总体的概念,而该结构体是PCB在Linux操作系统中的一种体现
  3. 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。

4. 什么是进程

4.1 进程VS程序

程序运行起来就叫进程,这句话可以算是对的,因为有程序运行就会有进程。
那么进程和程序之间具体是什么样的关系?观察下图:

在这里插入图片描述

这里可以举一个形象的例子:并不是你到了一个学校,你就是这个学校的学生,而是需要学校机构提供认证你是该校学生,这才能说“你是该校学生”。

上图也一样,并不是你把自己实现的可执行程序相关文件加载到了内存,就叫进程,还需要操作系统提供的内存控制块,它们加起来才会被“认证”为进程。

由此可知:进程=可执行程序相关文件+与进程相关的数据结构
其中的数据结构就是由操作系统自动生成的内存控制块。

4.2 操作系统如何管理进程

在这里插入图片描述

操作系统将多个进程按如图所示方式链接起来,并且提供每个内存控制块的编号数据(标识符pid),在需要找到某个进程的时候,可以通过该编号精确定位,并不需要访问到该进程本身的可执行程序里的代码内容,有了进程控制块,所有的进程管理任务与进程对应的程序毫无关系,而与进程对应的内核创建的该进程的PCB强相关!

在需要对其进行杀死进程或者其他操作时,可以通过数据结构的操作达到目的。

可以举一个例子:一个校长如果想要开除某位学生或者对其个人信息进行某种操作,并不需要直接找到该学生,访问其详细情况,直接在学校档案里按照学生独一无二的学籍号便可以找到该学生信息并进行相应操作。

5. 查看进程

5.1 通过系统调用获取进程标示符

  1. 进程id(PID)
  2. 父进程id(PPID)
 int main()
 {
     cout<<"child:"<<getpid()<<' '<<"parent:"<<getppid()<<endl;
     return 0;
 }

在这里插入图片描述

5.2 通过系统函数调用–fork函数

  1. 运行 man fork 认识fork
  2. fork有两个返回值
  3. 父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)
int main()
{
    fork();
    cout<<"child:"<<getpid()<<' '<<"parent:"<<getppid()<<endl;
    return 0;
} 

将会看到调用fork函数以后明显打印多了一次,这是因为两行分别是父进程和子进程打印的:

在这里插入图片描述

在这里插入图片描述

与此同时,id=1018同时作为29748的子进程和1019的父进程,29748作为bash进程,其具体的进程信息可以通过该指令查看:

ps axj | head -1 && ps ajx | grep 29748

在这里插入图片描述

fork以后意味着多了一个进程,那么对应的内核数据结构+进程的代码数据也多了一份。

如何理解这句话呢?

默认情况下,子进程会“继承”父进程的代码和数据,而其内核数据结构则是以父进程为模板来初始化一份。

  • 对于代码

既然是“继承”,那么父子代码此时应该是一模一样的(包括父进程以前拥有的代码),并且此时的代码是无法被修改的,因为代码是只读的。

  • 对于数据

但是对于数据来说,在父子进程间是“共享的”,这个共享很特殊,因为前提是进程之间具有独立性,那么这个共享只存在于特殊情况。每当有一个进程想要修改数据时,就会发生写时拷贝,这便是“共享”的真正意义。

这些方法本质都是为了维护父子进程的共享性和进程间的独立型。

6. 上下文数据

6.1 上下文数据如何产生

  • 观察图片

在这里插入图片描述

如图所示,寄存器中存放当前正在运行的进程的临时数据,若有多个进程同时在等待响应,就会形成等待队列,第一个处于R状态(运行状态)的PCB将被识别,然后将其对应的代码数据加载到CPU的寄存器中,就可以跑起来。

但是,不是每个程序的代码量都是很少的,若有很大数据的代码量,如果只让该PCB执行的话,其他进程就会被搁置。所以操作系统规定了每个进程单次运行的时间片;时间片可以理解为单个进程对应的运行时间,比如10ms,时间片消耗完以后就要切换下一进程。以这种方式,在用户的体验感来说,就好像多个进程同时在运行一样,而不是某个程序单独在跑,这本质是通过CPU快速切换进程实现的。

不停地切换未完成的进程,必将产生大量的临时数据,这些叫做上下文数据,需要暂时保存起来;这也就是为什么CPU中有这么多的寄存器。

6.2 如何处理上下文数据

CPU只有一个,进程有多个,进程在运行的时候要做到快速切换。

在切换进程的时候,要做到保护上下文和恢复上下文。

若此时有两个进程A和B在等待,A进程先运行,消耗完了时间片以后切换为B进程;此时A进程保存在CPU寄存器里的临时数据是有可能会被B进程覆盖的,因为A没有保护它自己的数据。

所以A在从CPU脱离的时候应该把自己产生的临时数据一并带走,这就不怕别的进程会覆盖那些数据了;而B进程在进入CPU运行时,也应该要进行恢复上下文,从上一次停下的地方开始运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

久菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值