文章目录
- [OS 操作系统](#OS 操作系统)
OS 操作系统
▶ 进程 和 线程 的区别
| 进程 | 线程 | |
|---|---|---|
| 从属关系 | ⼀个进程⾄少有⼀个线程,⼀个进程可以运⾏多个线程。 | 线程是进程的⼦任务,是进程内的执⾏单元。 |
| 定义 | 资源分配的最小单位 | CPU调度的最小单位 |
| 独立性 | 每个进程有独立的内存空间和资源 ,进程间 相互隔离 | 共享进程的内存和资源 |
| 创建/销毁开销 | 高开销,需创建/销毁整个进程的内存空间 | 低开销 ,仅需创建/销毁某个线程的内存空间 |
| 切换开销 | 高开销,需要保存整个进程的状态,涉及内存页切换等 | 开销较低,仅需保存和恢复少量的线程上下文 |
| 通信方式 | 管道、消息队列、共享内存、信号量、信号、socket套接字 | 共享内存、信号量 |
| 安全性 | 安全。因为进程间相互隔离,一个进程的崩溃不会影响到其他进程 | 没有进程安全,因为线程共享相同的内存空间,一个线程的错误可能会影响整个进程的稳定性。 |
▶ 进程间 通信方式
- 每个进程的用户地址空间独立,但是内核空间共享,进程之间的通信必须通过操作系统内核 。
管道
- 管道 ,就是操作系统内核⾥⾯的⼀串缓存,全程在缓存中完成数据传输通信。单向半双工通信 模式,从管道的⼀段写⼊数据,另⼀端读取,数据遵循 先进先出 的规则 。另外,管道传输的数据是 无格式的流且大小受限 。
| 匿名管道 | 命名管道 | |
|---|---|---|
| 适用场景 | 父子进程通信 | 无亲缘关系的任意进程通信(通过文件系统路径访问) |
| 存储位置 | 内存中 | 文件系统 |
| 生命周期 | 随进程的结束而销毁 ,无法持久化。 | 可长期存在 ,需手动删除。它的作用仅仅是提供一个全局可见的"名字",方便不同进程通过这个名字找到彼此并通信。数据本身只在内核的内存缓存中流动,不会写入磁盘文件。 |
- 管道的缺点
- 单向通信,若需要双向通信,必须创建两个独立的管道,增加了复杂性和资源开销。
- 通信数据是临时一次性的。一旦被读取,就会从内核缓存中移除。数据无法重复读取(仅一次消费);进程崩溃或退出时,未处理的数据会永久丢失。
- 传输效率限制,不适合频繁交换数据。频繁小数据写入时,每次写入会触发上下文切换(用户态↔内核态)。
- 内核缓冲区容量限制。写入超过缓冲区大小时,写入进程会被阻塞,直到数据被读取;
- 不适合传输复杂数据流。管道只能传输字节流,无法直接传递结构化数据(如对象、消息头)。
消息队列
- 消息队列 是 保存在操作系统内核中的消息链表 。在发送数据时,会分成⼀个⼀个独⽴的数据单元,也就是消息体(数据块),消息体是⽤户⾃定义的数据类型,消息的发送⽅和接收⽅要约定好消息体的数据类型,所以每个消息体都是固定⼤⼩的存储块,不像管道是⽆格式的字节流数据。如果进程从消息队列中读取了消息体,内核就会把这个消息体删除。
- 生命周期:随操作系统内核 ,若没有关闭操作系统,则消息队列一直存在。
- 消息队列 克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
- 消息队列的缺点
- 通信不及时。存在⽤户态与内核态之间的数据拷⻉开销:进程写⼊数据到内核中的消息队列时,会发⽣从⽤户态拷⻉数据到内核态的过程,同理另⼀进程读取内核中的消息数据时,会发⽣从内核态拷⻉数据到⽤户态的过程。
- 附件大小有限制,不适合较大数据的传输。内核限制⼀条消息的最⼤⻓度和⼀个队列的最⼤⻓度。
共享内存
- 共享内存 :进程之间各自拿出⼀块虚拟地址空间来,映射到相同的物理内存中 。这样一个进程写⼊的东⻄,其他的进程立马就能看到,不需要拷⻉来拷⻉去,传来传去,⼤⼤提⾼了进程间通信的速度。共享内存由⼀个进程创建,但多个进程都可以访问。
- 解决了 用户态和内核态的消息拷贝过程,最快 的通信方式 。
- 共享内存的缺点
- 多个进程同时访问共享内存,存在冲突。
信号量
- 信号量 其实是⼀个 整型的计数器,并不缓存 通信的数据 , 作为 进程间以及同⼀进程内不同线程之间 的 同步工具 ,⽤于实现进程间的互斥(强调单独占用资源)与同步(强调执行顺序)。例如:防⽌某进程正在访问共享资源时,其他进程也访问该资源。
- 信号量的 原子操作 :
- P 操作 :进入共享资源前,信号量-1,若结果<0,则表示资源已被占用,该进程进入阻塞等待;若结果>=0,表示资源可用,该进程正常继续执行。
- V 操作 :离开共享资源后,信号量+1,若结果<=0,则表示当前有阻塞的进程,则将对应阻塞的进程唤醒运行;若结果>0,则表示当前没有阻塞的进程。
信号
- 信号 是 异常情况下 的⼯作模式,唯一的 异步通信 机制。软件中断,用于通知接收进程某个事件已经发生,从而迫使进程执行信号处理程序 。
Socket 套接字
- 是⽀持TCP/IP 的⽹络通信的基本操作单元,主要⽤于在跨网络、不同主机 客户端和服务器上进程之间的网络通信 。
▶ 线程间 通信方式
| 通信方式 | 描述 |
|---|---|
| 共享内存 | 线程访问共享内存中的变量。直接访问,但需使用同步机制:互斥锁、信号量等。 |
| 条件变量 | 同步工具。线程 在条件不满足时进入等待状态,释放锁;当条件满足时,被通知的线程重新获取锁并继续执行 。 |
| 互斥锁 | 同步工具。保护共享资源,确保同一时间只有一个线程访问。 |
| 信号量 | 同步工具 |
| 读写锁 | 多读单写的同步机制 :允许多个线程同时读取共享资源,但写入操作需要独占访问。 |
▶ 同步、互斥
- 同步 是指多个并发执⾏的进程/线程之间协调和管理它们的执⾏顺序,以确保它们 按照⼀定的顺序或时间间隔执⾏。
例如,你想要和你的队友⼀起完成⼀个副本,你们需要相互配合,有时候等待对⽅的信号或者消息,有时候按照对⽅的要求执⾏某些动作,这就是进程同步。 - 互斥 指的是在 某⼀时刻只允许⼀个进程访问某个共享资源 ,当⼀个进程/线程正在使⽤共享资源时,其他进程/线程不能同时访问该资源。
例如,你想要使⽤⼀个祭坛来祈愿,但是这个祭坛⼀次只能被⼀个⼈使⽤,如果有其他⼈也想要使⽤,他们就必须等待你使⽤完毕后再去使⽤,这就是进程互斥。 - 解决同步和互斥的方法:信号量、互斥锁、临界区等。
▶ 进程 和 线程 的上下文切换
| 进程的上下文切换 | 线程的上下文切换 | |
|---|---|---|
| 切换的内容 | 虚拟内存、栈、全局变量等⽤户空间的资源 ,还包括了 内核堆栈、寄存器等内核空间的资源 。 通常会把交换的信息保存在进程的 PCB,当要运⾏另外⼀个进程的时候,我们需要从这个进程的 PCB 取出上下⽂,然后恢复到 CPU 中,这使得这个进程可以继续执⾏ |
当两个线程不是属于同⼀个进程:则切换的过程就跟进程上下⽂切换⼀样。当两个线程是属于同⼀个进程:因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器、程序计数器等不共享的数据 ; |
| 开销 | 大 | 小 |
▶ 死锁
- 死锁: 两个或多个进程在争夺系统资源时,由于互相等待对⽅释放资源⽽⽆法继续执⾏ 的状态。
死锁产生的条件
死锁只有同时满⾜以下四个条件才会发⽣:
- 互斥条件 :⼀个进程占⽤了某个资源时,其他进程⽆法同时占⽤该资源 。即:资源被占用时,其他进程不能占用。
- 请求保持条件 :⼀个 线程因为请求资源⽽阻塞的时候,不会释放⾃⼰的资源 。
- 不可剥夺条件 :资源不能被强制性地从⼀个进程中剥夺,只能由持有者⾃愿释放 。
- 环路等待条件 :多个进程之间形成⼀个循环等待资源的链,每个进程都在等待下⼀个进程所占有的资源。即:多个进程之间循环等待对方释放资源
避免死锁
只需要破坏上⾯⼀个条件就可以破坏死锁。
- 破坏请求与保持条件 :⼀次性申请所有的资源 。
- 破坏不可剥夺条件 :占⽤部分资源的线程进⼀步申请其他资源时,如果申请不到,可以主动释放它占有的资源。即:申请其他资源被阻塞时,先主动释放自己占有的资源 。
- 破坏循环等待条件:对资源排序,让所有进程按照相同的顺序请求资源,释放资源则反序释放。
▶ 虚拟内存
- 虚拟内存 在每⼀个进程创建加载的过程中,会分配⼀个连续虚拟地址空间,它不是真实存在的,⽽是通过映射与实际地址空间对应,这样就可以使 每个进程看起来都有⾃⼰独⽴的连续地址空间。
内存分段
- 内存分段 :通过分段把程序分离为若⼲个段 ,如代码分段、数据分段、栈段、堆段, 不同的段有不同的属性。通过 将不同的段或⻚⾯设置为只读、可读写、不可执⾏等权限 ,操作系统可以确保程序不会越界访问或修改其他段/页的内容,从⽽提⾼了系统的稳定性。
- 段表 ⾥⾯保存的是这个段的基地址、段的界限和特权等级等。虚拟地址是通过段表与物理地址进⾏映射的,分段机制会把程序的虚拟地址分成多个段,每个段在段表中有⼀个项,在这⼀项找到段的基地址,再加上偏移量,于是就能找到物理内存中的地址,
- 内存分段产生的问题
- 内存碎片
- 内碎片 :程序所有的内存都被装载到了物理内存,但是这个程序有部分的内存可能并不是很常使⽤,这也会导致内存的浪费。
- 外碎片 :某个程序被释放后,该块小内存不能和其他小内存一起联合起来被某个大内存的程序使用。
- 内存交换效率低
解决外碎片:将被释放程序后面的程序写到硬盘中,然后再重新从硬盘读取数据,写到原来被释放程序所在位置,内存重新连续起来。
- 内存碎片
内存分页
- 内存分⻚ :是把整个虚拟内存空间和物理内存空间分别切成⼀段段连续且尺⼨固定的内存空间即⻚(Page)。虚拟地址与物理地址之间通过⻚表来映射。
- 解决内存碎片
采⽤了分⻚,那么释放的内存都是以⻚为单位释放的,也就不会产⽣⽆法给进程使⽤的⼩内存。 - 解决内存交换效率
如果内存空间不够,操作系统会把其他正在运⾏的进程中的最近没被使⽤的内存⻚⾯给释放掉,也就是暂时写在硬盘上,称为换出(Swap Out)。⼀旦需要的时候,再加载进来,称为换⼊(Swap In)。所以,⼀次性写⼊磁盘的也只有少数的⼀个⻚或者⼏个⻚,不会花太多时间, 内存交换的效率就相对⽐较⾼。
| 分段 | 分页 |
|---|---|
| 用户可见 | 用户不可见 |
| 地址空间 二维 | 地址空间一维 |
| 段⻓过⼤,为其分配很⼤的连续空间会很不⽅便,段式管理会产⽣外部碎⽚很⽅便按照逻辑模块实现信息的共享和保护。 | 内存空间利⽤率⾼,不会产⽣外部碎⽚,只会有少量的⻚内碎⽚。不⽅便按照逻辑模块实现信息的共享和保护 |
▶ 用户态、内核态
- 操作系统中两种不同的执⾏模式,⽤于控制进程或程序对计算机硬件资源的访问权限和操作范围 。
| 用户态 | 核心态 |
|---|---|
| 只能访问受限的资源和执⾏受限的指令集,不能直接访问操作系统的核⼼部分 | 执⾏特权指令和访问操作系统的核⼼部分 |
| 不能直接访问硬件资源 | 可以直接访问硬件资源,执⾏系统调⽤,管理内存、⽂件系统等操作 |
| CPU不允许独占,即: CPU 能够被其他程序获取 | CPU 可以从⼀个程序切换到另外⼀个程序,并且占⽤ CPU 不会发⽣抢占情况 |
从用户态到内核态的转换类型
| 系统调用 | 硬件中断 | 异常 | |
|---|---|---|---|
| 场景 | 文件操作 网络通信 进程管理 | 时钟中断 I/O中断 键盘中断 | 故障 非法指令 |