前言:
计算机的发展是飞速的,从底层的算术逻辑单元ALU(Arithmetic & Logic Unit)、控制单元CU(Control Unit),到中央处理器CPU(Center Process Unit)。
发展是非常迅速的,如今我们需要要深刻认识计算机,学会计算机是如何"管理"所有的"程序"正常运行,如何合理"分配资源"。也就是我们的操作系统圆形程序的机制!!
操作系统:
操作系统是一组做计算机资源管理的软件的统称。
⽬前常⻅的操作系统有:Windows系列、Unix系列、Linux系列、OSX系列、Android系列、iOS系列、鸿蒙等。
操作系统的分层图:
1) 防⽌硬件被时空的应⽤程序滥⽤;2) 向应⽤程序提供简单⼀致的机制来控制复杂⽽⼜通常⼤相径庭的低级硬件设备。
内核:
硬件的驱动程序都是在内核中完成的。内核需要给很多的应用程序提供支持(API)
不同系统的API是不同的,在Java中,系统的API会被JVM进行封装
操作系统的内核是用C/C++写的。
指令:
CUP上的最小执行单元,这些单元都是用二进制的方式进行表示(机器语言)。
什么是进程:
每个程序在现如今的操作系统上运行时,操作系统会为该程序提供一系列的资源(包括硬件资源),供该程序完整的运行,该程序运行时,就被称之为一个进程:
我们也可以通过任务管理器来清楚看到:
当我们程序运行起来之后,为了描述它,我们使用类/结构体( PCB )把被管理对象的各个属性表示出来。
当多个程序运行之后,需要将它们组织起来,是利用数据结构(如双向链表)将他们穿起来,方便后续的增删查改!!
1.创建一个进程,就是创建PCB,并且把PCB插入到链表中
2.销毁进程,就是把PCB从链表中删除并释放
3.展示进程列表,相当于遍历链表的每个结点
PCB的相关属性:
PCB是一个结构体,里面包含了许多信息:
在Linux中,PCB被称为task_struct.
Pid(进程标识符):
pid是进程的身份标识。
每一个进程的pid是不同的。
如下:
内存指针:
描述了进程持有的内存资源。
每个进程在运行时都会被分配内存资源。
需要一组指针来区分,这个进程内存空间的具体位置、分配的内存空间中有哪些部分、以及每个部分的作用。
进程的内存空间,需要有专门的区域存储要执行的指令,以及指令依赖的数据。同时还要存储一些运行时产生的临时数据。
文件描述符表:
描述了进程持有的硬件资源。
进程涉及到硬件的操作时,就会按照文件的方式进行处理。
进程关联了哪些文件、能操作哪些文件,就是通过文件描述符表进行表示的
进程的调度信息:
什么是进程的调度,我们都是知道当一个进程运行起来之后,系统会为其分配内存空间资源,当然还会为其分配CPU的资源,因为CPU是有高算力,高速度等特性,但是此时问题就来了,以前一般CPU都是单核的,也就是一个CPU只能供一个进程使用,如果此时有多个进程同时运行,那么对CPU的分配是一件很困难的事了!
此时就出现了"调度"这一词,也就是操作系统对CPU的资源分配。
这里引入一个新词——并发执行:
并发:
什么是并发?
一起发生,同时发生,也就是进程同时发生的时候,这时候CPU会被分时复用,可以理解为将一个CPU执行的时间分成"时间片",这些时间片会分配给不同的进程。
由于这些时间片段时间非常短,多个进程一起运行的时候,所以感觉不到先后顺序。微观上就感觉在同时执行。
并行:
当代的CPU都非常高级了,一般都是4核或者8核CPU,也就是每一个核都可以利用起来!!
这时候所有的核都可以分配给所有的进程利用!!
这样的现象被称为并行执行。
总结:
现在这两种方式都被称为并发执行。
进程的状态:
就绪状态:
1.进程正在CPU上执行。
2.进程随时准备好,去CPU上执行
阻塞状态:
某个进程,某种执行条件不具备,导致这个进程暂时无法参与CPU的调度执行
比如进程等待用户输入
进程还有其他状态等待
进程的优先级:
- 操作系统在调度多个进程时,并非一视同仁
- 有的进程会具备更高的优先级,优先调度,更好的调配系统资源
进程的上下文:
进程从CPU离开之前,需要保存现场,把当前CPU中各种寄存器的状态,都记录到内存中(存档)
等到下次进程回到CPU上执行时,此时就可以把保存的这些寄存器的值,恢复回去。(读档)进程就会沿着上次访问到的位置,继续向后执行。
1.保存当前执行到哪些指令的寄存器(程序计数器)(x86_32位cpu上叫eip)
1.是一个2/4/8字节的整数,存的是一个内存地址。这个地址对应的就是程序下一条要执行指令的位置
2.一个exe文件,就包含了指令和数据,运行exe,操作系统就会把指令和数据加载到内存中(内存地址),CPU先从内存中取指令,然后执行指令。初始情况下,程序计数器就指向进程指令的入口(类型main方法)。每次取完一条指令,程序计数器的值就会自动更新,默认指向下一条(顺序执行)。如果遇到跳转类指令(jmp、jcmp、call)就会被设置成跳转到的地址。
进程的记账信息:
通过优先级机制,对不同的进程分配了不同权重的资源。
可能会出现极端情况,所有资源都分配给一个进程,其他没有分配到资源
记账信息会记录,当前进程持有CPU的情况(记录在CPU中执行了多久),可以作为操作系统调度进程的参考依据,从而对资源分配进行调整。
问题引出:
当一个程序运行时(.exe),操作系统会为其分配独立的内存资源等等,但是我们应该考虑以下几个问题:
1、每个程序运行之后,由操作系统分配资源,但是一个程序中有可能有多项任务,比如说一个QQ程序,里面既可以聊天,既可以打电话,既可以刷视屏等等,那么操作系统又是怎么管理这些小的任务的呢?
2、我们都知道以前的CPU大多都是单核的,那么只有一个CPU,操作系统又是如何将这一个CPU共给多个进程同时使用的呢?现在发展为多核CPU,又是如何分配CPU的资源的呢?
要回答这些问题时,我们再来谈谈"线程"。
什么是线程:
进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。
与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
线程中的PCB:
在进程的阶段我们就已将谈到了PCB,我们说每个击沉都有对应的PCB,这里的说法其实是不够严谨的,应该说每个线程都有自己的PCB,PCB中的性质有如下:
1、pid 每个线程都不一样
2、内存指针 同一个继承若干个线程的内存指针一样
3、文件描述符表 同一个继承若干个线程的内存指针一样
4、状态、上下文、优先级、记账信息 每个线程有自己的属性
5、tgid 同一个进程的tgid是同一个
进程与线程的区别总结:
线程具有许多传统进程所具有的特征,故又称为轻型进程(Light—Weight Process)或进程元;而把传统的进程称为重型进程(Heavy—Weight Process),它相当于只有一个线程的任务。在引入了线程的操作系统中,通常一个进程都有若干个线程,至少包含一个线程。
根本区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。
资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的
影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行。
这时候,我们来谈一谈我们提到的第二个问题,CPU是如何调度给线程的呢??
我们上述谈到的CPU调度给进程其实也不太严谨,那么当一个进程中就一个线程的时候,上述的结论是成立的,但是如果有线程呢??
也就是说这时有多个进程,每个进程中又有多个线程,那么这是该怎们办??
线程的调度方式:
其实CPU的调度都是针对线程来进行调度的,当然有以下两种调度方式:
1).用户级线程调度。 由于内核并不知道线程的存在,所以内核还是和以前一样,选择一个进程并给予时间控制。由进程中的调度程序来决定哪个线程运行。
2).内核级线程调度。 内核选择一个特定的线程运行,不用考虑线程在哪个进程,对其赋予一个时间片,若超过时间片就将其挂起。
这时候就能合理解释进程和线程的调度问题!!!!