✨✨hello,愿意点进来的小伙伴们,你们好呐!
🐻🐻系列专栏:【JavaEE初阶】
🐲🐲本篇内容:详解进程与线程
🐯🐯作者简介:一名现大二的三非编程小白,日复一日,仍需努力。
- 进程相关:
- 进程的概述:
- 进程的创建:
- 进程的描述:
- 进程的组织:
- 操作系统的调度:
- 内存管理:
- 进程缺陷:
- 线程相关:
- 进程与线程的区别:
进程相关:
进程的概述:
我们可以理解为一个跑起来的程序就是一个进程,在电脑任务管理器界面就可以看到很多进程在运行
这些应用与后台进程就都是此时电脑上的进程数
我们要记住进程的前提是运行中的,没有运行起来的就叫程序,不叫做进程.
如现在在我的电脑中躺着的Feishu.exe,它就是叫做一个程序,安安静静地躺在E盘中
进程的创建:
🚓🚓进程的创建操作系统会分配对应的资源给创建的进程使用
比如:在下列任务管理器界面可以看得到每一个进程都有 CPU,内存,磁盘,网络,GPU资源,还有其他的一些资源
🚗🚗这些就是进程创建的时候分配给进程的资源,但是在进程中这些资源的占有量并不是固定不变的
这就好比一个人刚出生的时候上天赋予你五官的,最开始每个人的五官是差不多的,但是有的人长大就变得越来越好看,有些就止步不前,
🚕🚕 在上图中,我们会发现每一个进程后面都有对应分配的资源, 由此可见操作系统分配资源就是对一个一个的进程来分配的,进程其实就是操作系统分配资源的基本单位
进程在创建的时候操作系统的内核就会对创建的进程进行管理 — 描述 + 组织
且进程是一个软件资源
进程的描述:
🚙🚙描述进程就是对进程所拥有的属性特征来进行描述,讲清楚其特征
在操作系统内核中来描述进程属性的是使用C语言的结构体(操作系统大多数都是C/C++来编写的),前人对这个描述进程的结构体起了一个特殊的名字 – PCB(简称进程控制块)
这个PCB到底描述了进程哪些特性呢?
1. pid : 进程的唯一身份标识符,每一个进程只有一个pid
2. 内存指针 : 描述了自己所指向的内存.
3. 文件描述器: 硬盘上的其他文件资源.(内存,硬盘,内存,硬盘,网卡,CPU)
进程的组织:
🚌🚌操作系统内核使用了一种类似于双向链表的数据结构来组织进程,将描述进程的PCB都给串起来
创建一个进程本质就是往描述进程的双向链表中插入该进程,销毁一个进程就是在链表中将PCB节点删除掉,在控制面板看得到进程,本质上其实就是遍历整个PCB链表,将其打印出来
操作系统的调度:
在分配进程资源的时候,其他硬件资源是很好分配的,都是CPU资源有限,就不是很好分配了,就像我们口袋里的💴,不是很好分配,每一次分配我们都要头脑风暴
🚐🚐我们将CPU分配给进程称为进程调度:
我们来了解一下调度的核心 — 并行与并发
并行
🚜🚜在两个进程执行的过程中,每一个进程都是给不同的CPU执行的,这个时候进程就是微观与宏观上的同时执行,称为并行,
并发
🚘🚘在微观上,同一时刻一个核心只能运行一个进程,但是有多个进程在该CPU上快速的切换执行,比如这个CPU一下子运行微信,一下子子切换运行qq,这个时候因为CPU的切换速度很快,在我们感知不到的范围内,所以我们就感觉好像多个进程是同时运行的,其实并不是
但是并行与并发其实是我们感知不到的,所以一般情况下我们都将并行与并发称为并发
1. 进程的状态:
进程的状态是因为进程有调度,所以才会导致有进程的有不同的状态:
🚚🚚就绪状态: 这个状态下,进程已经准备好了随时都可以去CPU执行.
🚒🚒运行状态: 这个状态是正在执行的进程所拥有的.
但是在很多操作系统都不会分辨运行状态与就绪状态
🚑🚑阻塞状态 : 当前这个进程因为某些因素无法到CPU上执行,这个时候就形成了进程阻塞
2.进程优先级:
🚛🚛在操作系统中队进程的调度也不是一碗水端平的,会有调度优先级,它会自己判断哪个进程需要的执行时间多,就排给谁执行,就像老师喜欢学习成绩好的学生一样噢
3.上下文:
CPU在切换进程执行的时候,需要把进程执行的中间状态记录下来,保存好.,下一次这个进程再上CPU来执行的时候,就可以直接恢复到上一次执行的状态继续执行,
上下文本质上就是存档的内容,进程中的上下文就是存在CPU寄存器内,CPU的存储模块,保存的就是程序运行过程中的中间结果
保存上下文就是把这些CPU的寄存器的值记录到内存中,
恢复上下文就是将内存中的数据恢复到寄存器中
4. 记账信息:
记账信息就是操作系统来统计每个进程在CPU中占用的时间与执行的指令数目,根据这个决定下一个阶段是如何调度的
内存管理:
操作系统会对每一次进程分配相应的内存地址,但是进程获取到的内存地址其实并不是真实的物理地址 ,程序中所获取到的内存地址,并非真实的物理内存地址,而是通过一层一层的抽象,虚拟出来的地址. 而为什么要这样子呢?
我们可以想想,要是进程得到的是真实的地址会导致什么样的后果;
如果代码不小心出现了bug,在操作进程1的内存地址不小心内存越界,那么就有可能访问到进程2的内存地址,那么这个时候就可能导致线程1与2都出现了bug,进程1将进程2给搞坏了,所以使用真实的地址时,会导致很多不可预见的内存错误
针对上述的情况,操作系统使用了MMU硬件设备来进程使用的内存地址进行"隔离"操作,引入了虚拟地址空间~~
在进程PCB的描述中不再使用真正的物理地址了,而是使用虚拟地址,用操作系统与MMU硬件设备来负责进行1虚拟地址到物理地址的转换.使用该设备将避免进程之间产生影响,如果有一个进程的地址访问越界了,会直接返回一个异常,导致进程崩溃,这样子就不会影响到其他的进程了.
这时候进程相互影响的问题解决了,但是有些时候需要两个进程的交互又该怎么办呢?
这个时候就在隔离性的基础上开个口子,搞一个多个线程都可以访问的公共空间,基于这个空间来进行数据交互
进程缺陷:
进程的存在就是来解决 “并发编程” 这个问题的,因为CPU进入了多核心时代,要想进一步提高程序的执行速度,就需要充分利用CPU的多核资源.
但是进程实在是太重了>>>> 因为进程之间是隔离的,所以 创建,销毁,调度 一个进程开销很大,这个开销就在于资源分配与回收上>>因为一个进程就对应一个硬盘资源,对应的申请资源,释放资源
在这种情况下,线程就应运而生,线程就叫做轻量级进程,在解决并发情况下,让创建,销毁,调度的速度更快,因为把申请资源,释放资源的操作节省下来.接下来我们来看看线程为什么会节省这些资源呢?
线程相关:
进程就包括了线程,一个进程空语包括多个线程或者一个线程,进程一定不能没有线程,
但是线程为什么会节省创建,销毁线程的资源呢?
因为多个线程是在一个进程中的,那么一个进程的内存,文件资源,硬件资源,都可以给多个线程来使用,那么就会节省了这些资源的创建销毁的开销,这个时候就第一次创建线程的时候开销是比较大的,后续的线程都是与第一个线程创建的时候所申请的资源共用一份资源
所以当一个进程有多个线程的情况下,操作系统调度的是以线程为单位进行调度的 – 每个线程都是独立在CPU上调度的 => 线程是操作系统调度的基本单位, 每个线程都有自己的执行逻辑 , 所以说,一个CPU执行的是一个线程,但是CPU在哪个线程也是不确定的,取决于操作系统背后的调度.
一个线程也是通过一个PCB来描述的,这样子的话一个进程可以有多个PCB,但是在一个进程中pid是一样的,内存指针和文件描述表是一样的
那么对于调度来说,线程来接管和调度相关的一切,进程专门负责分配系统资源,当一个进程只有一个线程的情况下,那么调度是对于进程来说了
线程会大大的提高速度,都是太多线程也会导致一系列的问题:
- 线程太多会导致CPU,内存,带宽资源的耗尽.
- 多个线程对同一个数据操作的时候,就会出现打架情况,所有线程都去争取这个数据,最后导致线程安全问题,这个问题在多进程模型下就不会出现,因为多进程是隔离的模型
- 一个线程抛异常,有可能导致整个进程都带走了
所以在使用多线程模型的情况下,我们要考虑好线程安全性的问题
进程与线程的区别:
1. 多线程会提高效率,多进程更安全
2.多进程是天然的资源隔离模型,不容易触发,但是在进行进程通讯的时候,多个进程访问一个资源,也会出现问题
3.多线程天然就是资源共享的,所以争夺同一个资源,非常容易触发线程安全问题.
4.操作系统调度看的是PCB