🏀🏀🏀来都来了,不妨点个关注!
🎧🎧🎧博客主页:欢迎各位大佬!
文章目录
- 1. 操作系统
- 1.1 什么是操作系统
- 1.2 操作系统主要的功能
- 2. 进程
- 2.1 什么是进程
- 2.2 通过PCB描述一个进程
- 2.3 进程的调度
- 2.4 PCB的管理
- 2.5 内存管理
- 2.6 进程间通信的方式
- 3.线程
- 3.1 什么是线程
- 3.2 有了进程为什么还要有线程
- 3.3 进程与线程的联系和区别
1. 操作系统
1.1 什么是操作系统
操作系统本质上是运行在计算机上的软件程序,对上,它负责给软件运行提供稳定的环境,对下,它要管理好各种硬件设备。我们可以通过以下的图文进行理解:
1.2 操作系统主要的功能
从资源管理的角度来看,操作系统主要有六大功能:
- 进程和线程的管理:进程的创建、撤销、阻塞、唤醒,进程间的通信等。
- 存储管理:内存的分配和管理、外存(磁盘等)的分配和管理等。
- 文件管理:文件的读、写、创建及删除等。
- 设备管理:完成设备(输入输出设备和外部存储设备等)的请求或释放,以及设备启动等功能。
- 网络管理:操作系统负责管理计算机网络的使用。网络是计算机系统中连接不同计算机的方式,操作系统需要管理计算机网络的配置、连接、通信和安全等,以提供高效可靠的网络服务。
- 安全管理:用户的身份认证、访问控制、文件加密等,以防止非法用户对系统资源的访问和操作。
可以看到操作系统的上述功能中,进程和线程管理和我们今天要讲的进程与线程关系密切。
那么为什么要进行进程的管理呢,那当然是因为进程太多了才需要管理嘛,就比如我们上学,学校也都有会一个学生管理系统,里面就记录着我们每个学生的信息。下面我们分别从进程和线程两个角度进行讲解。
2. 进程
2.1 什么是进程
一个运行起来的程序就是进程,而我们电脑中的.exe文件就是一个可执行的文件(程序),当双击这个.exe文件,这个程序跑起来就形成了一个进程。关于这个我们可以通过任务管理器查看,如下图:
我们从上面两种图都可以观察到我们的计算机上运行着许许多多的进程,我们在最开始提到过,操作系统的一大功能就是进行进程的管理,那么它是如何对进程进行管理的呢?其实就分为两步,下面我们就来介绍:
- 描述一个进程:使用结构体/类把一个进程有哪些信息描述出来
- 组织这些进程:使用一定的数据结构将这些结构体/对象组织在一起
2.2 通过PCB描述一个进程
在上面我们提到对进程管理分为了两步,第一步就是描述该进程,而在操作系统中,用于描述系统进程状态的数据结构通常被称为进程控制块(Process Control Block, PCB)。而PCB有很多的属性,这里我们将介绍几个核心的:
- pid: 进程的唯一身份标识(这个我们在Linux常用命令章节里提到过)
- 内存指针:表示当前进程使用的内存是哪一部分(进程要运行起来就需要消耗一些硬件资源,这其中就包括了内存)
- 文件描述符表:文件描述符表是一个数据结构,用于记录当前进程打开了哪些文件。当进程需要操作文件时,它会在文件描述符表中分配一个表项,并构造一个结构体来描述该文件的相关信息。
- 进程状态:描述当前进程所处的状态
主要为两个状态:
就绪态:该进程已经准备好了,随时可以在CPU上运行
阻塞态:该进程暂时无法在CPU上运行 - 进程的优先级:优先级用于决定操作系统调度进程的顺序。优先级高的进程会获得更多的CPU资源
- 进程的上下文:进程的上下文就是记录当前进程执行到哪里的"存档记录",进程在离开CPU的时候就需要把进程执行的中间结果进行"存档",等下一次回到CPU上的时候再恢复之前的"存档"。从上一次的结果继续往后面执行。(类似于我们玩游戏玩到一半不玩了进行存档退出,下一次玩的时候再进行读档,回到之前玩的地方继续往后面玩)
- 进程的记账信息:统计了每个进程在CPU上执行了多久了,可以作为进程调度的参考依据
其中,第4、5、6,7点都是和进程的调度有关的,下面我们先来介绍一些什么是进程的调度
2.3 进程的调度
在计算机操作系统中,进程调度是指按照某种策略或算法,从就绪队列中选择一个进程,将处理机分配给该进程,使之执行的过程。
那为什么要有进程的调度呢
我们先来了解一下CPU,我们的一个个程序能够运行起来,都是依靠着CPU的调度,我们可以打开任务管理器来看看CPU的相关属性,如下图:
这个表示我自己计算机的CPU有8个 物理核心,而一个物理核心相当于两个逻辑核心,这表示CPU同时能处理16个任务,此时就有人想问了但我们的计算机上同时运行的进程可不止16个,那CPU是如何处理的呢?这里我们介绍两个核心概念
- 并行:两个核心同时执行两个任务(进程),此时这两个任务就是并行执行的。
- 并发: 一个核心先运行进程1运行一会后再运行进程2运行一会后再运行进程3,只有切换的够快,这里的进程1、2,3看起来就像是同时执行的一样。
这也就告诉我们,虽然我的CPU只能同时执行16个任务,但通过并行+并发,我们就可以同时处理多个任务了,通常我们也将这里的并行+并发统称为并发。
2.4 PCB的管理
操作系统往往是使用双向链表的方式将PCB组织起来,这样进程相当于链表中的节点,方便管理时进行增删改查的操作
- 创建一个进程,即创建一个链表的节点
- 销毁一个进程,即把链表的节点删除
- 遍历进程列表,即遍历链表
2.5 内存管理
操作系统对内存资源的分配,采用的是空间模式 —— 不同进程使用内存中的不同区域,互相之间不会干扰。
而操作系统给每一个进程分配的内存空间都是以“虚拟地址空间”的方式分配的。
这里肯定就会有人要问了,有直接的物理地址,为什么不直接给每一个进程直接分配物理地址。我们用下面进程直接访问实际物理地址的图片来介绍:
上图就是每个进程都是直接访问物理内存的地址,此时可能就会产生一个比较严重的问题,万一进程1的代码出现了bug(比如数组下标越界,野指针…),可能就会连带着把进程2搞崩溃了。
下面我们就来看看操作系统是如何通过使用虚拟内存来解决这个问题的:
站在进程自身的角度看,它们的内存地址就是0x00aa-0x00ff,这里访问的内存地址就会被操作系统自动映射到真正的物理地址上,但是进程自身是感知不到实际的物理地址是啥的。
此时如果进程1代码出bug,就没有什么影响,因为任何一个内存操作都需要通过页表翻译,比如出现野指针0x11aa,拿着这个地址,页表无法映射也就不会修改真正物理内存,即不会对进程2的内存数据进行干扰。
- 页表:操作系统使用页表来维护虚拟地址到物理地址的映射关系。页表是一种数据结构,它记录了每个虚拟页(通常是4KB大小)对应的物理页号。
- 地址翻译:当CPU执行指令并需要访问某个内存地址时,它首先会检查这个地址是虚拟地址还是物理地址。如果是虚拟地址,CPU会通过页表将其转换为物理地址,然后访问物理内存。
- 缺页异常:如果CPU在访问某个虚拟页时发现该页没有在物理内存中(即发生了缺页),它会产生一个缺页异常。操作系统会捕获这个异常,并从磁盘或其他存储介质中加载缺失的页到物理内存中,然后更新页表以反映这一变化。
2.6 进程间通信的方式
在上面我们说了操作系统给每个进程都分配了一块独立的虚拟地址空间,这保证了进程间的地址空间隔离。一个进程无法直接访问另一个进程的内存,从而避免了内存冲突和数据损坏。
即各个进程互相之间是无法感受到对方存在的,是相互独立的,这样进程之间互相具备"隔离性",但有时候需要进程之间进行交互,相互配合。
此时就有了进程间的通信:即在隔离性前提下,找一个公共区域,让进程借助这个区域完成数据交换。
目前,主流操作系统提供的进程通信机制有如下:
- 管道
- 共享内存
- 文件
- 网络
- 信号量
- 信号
- 套接字(Sockets)
其中,网络是一种相对特殊的 IPC 机制,它除了支持同主机两个进程间通信,还支持同一网络内部非同一主机上的进程间进行通信。
3.线程
3.1 什么是线程
线程(Thread) 也被称为轻量级进程,更加轻量。多个线程可以在同一个进程中同时执行,并且共享进程的资源比如内存空间、文件句柄、网络连接等。举例:你打开的微信里就有一个线程专门用来拉取别人发你的最新的消息。
3.2 有了进程为什么还要有线程
- 进程切换是一个开销很大的操作,线程切换的成本较低。
- 线程更轻量,一个进程可以创建多个线程。
- 多个线程可以并发处理不同的任务,更有效地利用了多处理器和多核计算机。而进程只能在一个时间干一件事,如果在执行过程中遇到阻塞问题比如 IO 阻塞就会挂起直到结果返回。
- 同一进程内的线程共享内存和文件,因此它们之间相互通信无须调用内核。
3.3 进程与线程的联系和区别
联系:一个进程中可以有多个线程,这些线程共享一份堆和方法区(jdk1.8之后称为元数据区)资源,同时每个线程有自己的虚拟机栈、本地方法栈和程序计数器。这点我们在JVM篇里介绍过。
区别:
- 进程是操作系统资源分配的基本单位,线程是操作系统调度执行的基本单位(这也告诉我们上述我们介绍的进程的调度,其实是对进程里的线程的调度)
- 进程具有独立性,一个进程不会影响另一个进程,但在同一进程的多个线程之间,一个线程挂了,可能会把整个线程带走,影响其它线程。
- 进程开销大,消耗资源多,线程执行开销小,但不利于资源的管理和保护
本次的分享就结束了,感谢支持!