LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

操作系统之进程与线程

admin
2025年6月19日 17:16 本文热度 7003

导读

大家好,这里是编程Cookbook。本文详细介绍操作系统中与进程和线程相关的核心知识点,包括它们的基本概念、区别与联系、调度策略、通信方式、同步机制、I/O 模型与锁、以及死锁问题的处理策略。

目录

  • 概念与区别

    • 进程

    • 线程

    • 进程 VS 线程

    • 协程

    • 协程 VS 线程

    • 一个进程可创建的线程数量

    • 进程和线程的地址空间

  • 状态管理与调度

    • 进程状态

    • 调度算法

    • CFS 调度器(Linux)

    • 进程终止方式

  • 特殊进程

    • 僵尸进程(Zombie Process)

    • 孤儿进程(Orphan Process)

  • 切换与上下文

    • 进程的切换过程

    • 调度 vs 切换

    • 线程的切换过程

    • 上下文信息

    • 进程 vs 线程切换的区别

  • 通信(IPC)方式

    • 进程间通信方式

    • 线程间通信方式

    • 总结对比

  • 进程同步

    • 临界资源

    • 同步遵循的准则

    • 实现临界区互斥的基本方法

  • 基本内容

    • 常见锁

    • 锁的优缺点

    • 悲观锁 vs 乐观锁

  • 死锁

    • 概念

    • 死锁的四个必要条件(同时满足才可能发生死锁)

    • 死锁的处理策略


进程与线程

概念与区别

进程

为了更好的描述和控制程序的并发,实现操作系统的并发性和共享性,引入了进程的概念,为每一个进程分配一个专门的数据结构:进程控制块PCB(常驻内存),保存运行期间进程的数据,PCB 是进程存在的唯一标志。

进程是操作系统中进行资源分配和调度的最小单位, 是正在运行的程序的实例。每个进程都有自己独立的地址空间、数据栈以及其他用于跟踪进程执行的辅助数据(如文件描述符、寄存器状态等)。

线程

线程是“轻量级进程”,它是基本的CPU执行单元,也是程序执行流的最小单元,由线程ID、程序寄存器、寄存器集合和堆栈组成(即 CPU 调度的基本单元)。线程控制块(Thread Control Block, TCB):保存运行期间线程的数据,TCB 是线程存在的唯一标志。

线程是 CPU 调度(程序执行)的最小单位,是进程中的一个执行流。一个进程可以包含多个线程,它们共享该进程的地址空间、文件描述符、堆等资源,但每个线程有独立的栈空间和寄存器状态。

进程 VS 线程

引入线程是为了提高程序的并发性能。相较于进程,线程更加轻量,切换开销更低,适合处理高并发、高频率的任务,如 Web 服务、爬虫、图像处理等。他们的区别如下:

对比点
进程
线程
地址空间
互相独立
共享所属进程的地址空间
通信方式
开销较大(需IPC)
开销较小(可共享内存)
调度开销
创建和切换开销较大
创建和切换更轻量
崩溃影响
一个进程崩溃不影响其他进程
一个线程崩溃可能影响整个进程

进程和线程的关系

  1. 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
  2. 资源分配给进程,同一进程的所有线程共享该进程的所有资源。
  3. 线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
  4. 处理机分给线程,即真正在处理机上运行的是线程。
  5. 线程是进程内的一个执行单元,也是进程内的可调度实体。

线程与进程的区别

  • 调度: 进程是资源分配和调度的一个独立单元;而线程是 CPU 调度的基本单元。

  • 并发性: 不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行。线程并发执行过程中要进行同步和互斥,因为它们共享同一进程的所有资源。

  • 拥有资源: 进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。并且线程共享整个进程的资源(寄存器、堆栈、上下文)。

  • 系统开销: 线程是轻量级的进程,它的创建和销毁所需要的时间比进程小很多,所以进程在切换和创建销毁时,耗费的资源较大,系统开销较大。

  • 健全性: 进程有独立的地址空间,进程崩溃后,在保护模式下不会对其他的进程产生影响;线程有自己的堆栈和局部变量,但没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮。

  • 创建和销毁: 进程的创建调用 fork 或者 vfork,而线程的创建调用 pthread_create;进程结束后它拥有的所有线程都将销毁,而线程的结束不会影响同个进程中的其他线程的结束。

协程

协程是一种用户态的轻量级线程,是由用户控制的执行单元,拥有独立的执行上下文和栈。它的调度和上下文切换不依赖操作系统内核,而是由程序显式控制切换,可以在函数中间挂起和恢复执行,非常适合处理 I/O 密集型任务。

协程 VS 线程

协程的切换完全在用户态完成,性能远优于线程,非常适合大量 I/O 场景(如网络请求、数据库操作),可以极大地减少上下文切换开销。他们的主要区别如下:

对比点
协程
线程
所在空间
用户态
内核态
切换成本
极低(无需系统调用)
较高(涉及内核态切换)
并发模式
非并行(需配合事件驱动)
可并行(依赖多核)
使用场景
高并发I/O、异步任务
CPU密集、并行处理
  • 协程本身不具备并行能力,但可以通过线程调度多个协程并发运行;
  • 线程的调度是由内核完成,涉及从用户态到内核态的切换

一个进程可创建的线程数量

理论上,线程数量受限于操作系统和硬件资源(如内存)。Linux 中,线程本质上是轻量级进程,一个进程可以创建的线程数没有固定上限,但在 Linux 系统中,一般受限于:

  • 每个线程的栈空间大小(默认 8MB)
  • 系统虚拟内存总量
  • 操作系统配置(如 ulimit)
  • 实际上通常能创建的线程数在 几千到几万个之间。

进程和线程的地址空间

关于 进程和线程的地址空间,我们可以从操作系统的资源隔离和共享机制来理解它们的区别:

进程的地址空间

每个进程都有独立的地址空间,包括以下几部分:

区域
描述
代码段(Text)
存储可执行代码(只读)
数据段(Data)
存储已初始化的全局变量与静态变量
BSS段
存储未初始化的全局变量与静态变量
堆(Heap)
动态内存分配(如 malloc/new)使用的区域,向上增长
栈(Stack)
存储函数调用的局部变量和返回地址,向下增长
共享库映射区
映射动态链接库使用的内存区域
内核空间映射区
操作系统为每个进程保留的内核映射区域(在某些架构中)

不同进程之间的地址空间互不影响,隔离性强,进程间通信(IPC) 需要特殊机制(管道、共享内存等)。

线程的地址空间

线程是进程中的“执行单元”,共享进程的地址空间,但每个线程有自己独立的一小块空间:

空间类型
是否共享
说明
代码段
共享
所有线程执行相同代码
堆空间
共享
线程之间可以访问同一动态内存
全局变量
共享
所有线程都能访问同一个全局变量
文件描述符表
共享
打开的文件在进程内共享
栈空间不
共享
每个线程都有自己的独立栈,存储私有局部变量、返回地址等
线程局部存储(TLS)不
共享
线程私有数据,避免冲突

总结对比表

属性
进程
线程
地址空间是否独立
是
否(共享进程地址空间)
堆/全局变量是否共享
不共享
共享
栈是否共享
不共享
不共享(每个线程独立)
通信方式
IPC,如管道/共享内存
直接共享内存或同步机制
创建/切换开销
较大(需完整资源分配)
较小(仅栈和调度信息)

每个进程拥有完整独立的地址空间,而线程是进程内的执行单元,共享进程的地址空间但拥有自己的栈和线程私有数据(TLS)。线程之间共享内存,因此通信成本低,但需注意同步与线程安全问题。


状态管理与调度

进程状态

操作系统中的进程通常具有以下几种状态:

  • 就绪(Ready):进程已经获得除 CPU 之外的所有资源,等待 CPU 分配;
  • 运行(Running):进程正在使用 CPU 执行;
  • 阻塞(Blocked / Waiting):进程正在等待某个事件(如 I/O)完成,无法继续执行;
  • 新建(New):进程正在创建中;
  • 终止(Terminated / Exit):进程执行完毕或被中止;
  • (有些系统还有:挂起状态,比如“就绪挂起”、“阻塞挂起”,用于内存调度)

进程在操作系统中会在不同状态之间转换,常见状态包括就绪、运行、阻塞三种,状态转移机制如下:

  • 运行态 → 阻塞态:进程因等待 I/O 或锁等资源主动放弃 CPU(主动行为);
  • 阻塞态 → 就绪态:等待的资源就绪,操作系统唤醒进程(被动行为);
  • 运行态 → 就绪态:时间片用完或被调度器抢占,进程让出 CPU(被动行为);
  • 就绪态 → 运行态:操作系统调度器分配 CPU 给该进程(被动行为)。

调度算法

调度分级

调度类型
又称
说明
作业调度
高级调度
从外存中的后备作业中选择作业,分配资源并建立进程,使其获得竞争处理机的权利。
内存调度
中级调度
选择挂起状态的进程重新调入内存(即从外存加载到内存)。
进程调度
低级调度
从就绪队列中选择一个进程,将处理机分配给它运行。

发生频率比较:高级调度 < 中级调度 < 低级调度


调度方式

调度方式
适用场景
特点说明
非抢占调度方式
批处理系统
当前进程运行完前不会被剥夺处理机。
抢占调度方式
分时系统、实时系统等
当前进程运行中可能会被操作系统剥夺处理机。

常见调度算法

操作系统使用调度算法决定哪个进程/线程优先获得 CPU 时间。常见算法如下:

调度算法
简要说明
先来先服务(FCFS)
按照进程到达时间顺序执行,简单但可能导致部分进程“饥饿”。
短作业优先(SJF)
优先执行估计运行时间最短的作业,能显著降低平均等待时间,但可能导致长作业饥饿。
高响应比优先(HRRF)
响应比 = (等待时间 + 服务时间) / 服务时间,选择响应比最高的作业执行,兼顾等待时间与服务时间。
时间片轮转(RR)
每个进程分配一个时间片,时间用完即切换,提高系统响应性,适合分时系统。
优先级调度
根据进程优先级高低进行调度,支持抢占/非抢占两种策略,可能出现低优先级进程饥饿问题。
多级反馈队列(MLFQ)
使用多个优先级就绪队列,进程可动态在队列间移动,结合了时间片轮转和优先级调度,适应性强。
完全公平调度器(CFS)
Linux 的默认调度器,使用红黑树按“虚拟运行时间”调度进程,实现按权重“公平分配 CPU 时间”。

CFS 调度器(Linux)

CFS(Completely Fair Scheduler)是 Linux 从 2.6.23 版本引入的默认进程调度器,核心目标是实现“尽可能公平”的调度:

  • 每个进程维护一个“虚拟运行时间(vruntime)”,运行时间越多,优先级就越低;
  • 所有就绪进程按 vruntime 排序,使用红黑树(RBTree)存储,红黑树最左侧节点拥有最高调度优先级;
  • 支持进程权重(如 nice 值),可实现公平但带权的调度。

CFS 支持平衡交互性与吞吐量,是目前 Linux 系统通用场景下的主力调度器。


进程终止方式

操作系统中,进程终止主要有以下几种方式:

  • 正常终止(Normal exit):进程主动调用 exit() 或返回主函数,正常结束;
  • 错误终止(Error exit):进程由于运行错误(如段错误、非法操作)被终止;
  • 被其他进程终止(Killed by another process):如通过 kill(pid, SIGTERM) 信号强制结束;
  • 被操作系统终止(Aborted by OS):如内存溢出、非法访问、资源限制等被系统强制终止。

特殊进程

僵尸进程(Zombie Process)

定义

当一个子进程执行完毕(终止)后,其退出信息(如退出码)还没被父进程回收(通过 wait() 或 waitpid()),该子进程就进入僵尸状态,成为 僵尸进程。 它在 进程表中保留一项记录,用于父进程获取信息。

带来的问题

僵尸进程已经终止,不会占用CPU和内存,但也会有其他的问题:

  • 僵尸进程会占用系统的进程表项(PCB,用于保存退出状态),而进程表项数量是有限的;
  • 如果大量僵尸进程堆积,可能会导致 系统无法创建新进程,引发系统资源耗尽;
  • 极端情况下可能导致系统不稳定甚至崩溃。

解决方案

  1. 让父进程调用 wait() / waitpid() 回收子进程资源;
  2. 如果父进程忘记回收,可以杀掉父进程,让子进程变成 孤儿进程,由 init(或 systemd)接管后,init 会负责回收;
  3. 使用信号机制(如 SIGCHLD)信号通知父进程子进程已退出,触发回收机制;

孤儿进程(Orphan Process)

定义

当一个子进程还在运行,而它的父进程已经退出,该子进程会成为孤儿进程。

操作系统会自动将其交给 PID 为 1 的 init/systemd 进程 进行接管和管理。

带来的问题

  • 孤儿进程不会像僵尸进程那样占用系统资源,因为 init/systemd 会自动回收它们的状态;

  • 但如果这些孤儿进程本身是无意义的或无限循环,可能会导致:

    • 占用大量 CPU 或内存资源;
    • 增加系统负担,系统性能下降。

解决方案

  1. 定期检查系统中 PPID=1 的进程(ps -ef | awk '$3==1');
  2. 如果是异常程序导致的,应修复程序逻辑或添加守护策略;
  3. 可使用 kill 杀掉异常的孤儿进程。

$3 表示第三列,也就是 PPID(父进程 ID),当该值为 1 时,表示其父进程是 init(PID 为 1)。

切换与上下文

进程的切换过程

进程切换是指 CPU 从当前正在运行的进程切换到另一个进程的过程,导致运行环境发生实质性变化。

过程步骤解释如下:

  1. 保存处理机上下文 保存当前进程的 CPU 寄存器状态(包括 PC、SP、通用寄存器等)到该进程的 PCB 中。

  2. 更新 PCB 信息 修改当前进程的状态(如从“运行”改为“就绪”或“阻塞”),并记录相关信息。

  3. 将 PCB 移入对应队列

    • 如果是主动等待资源 → 阻塞队列
    • 如果是时间片用完 → 就绪队列
  4. 选择新的进程并更新其 PCB

    • 调用调度算法(如 CFS、RR)从就绪队列选中下一个进程。
    • 将选中的进程 PCB 状态更新为“运行”。
  5. 更新内存管理的数据结构

    • 切换页表(Page Table Base Register)以映射新进程的虚拟内存空间。
    • TLB(Translation Lookaside Buffer)失效,需要刷新。
  6. 恢复处理机上下文

    • 加载目标进程的上下文(寄存器、PC、SP 等)
    • 跳转执行

调度 vs 切换

项目
描述
调度(scheduling)
是“决定哪个进程获得 CPU”的策略决策行为。调度器根据优先级、时间片等信息选择合适进程。
切换(switching)
是“将 CPU 交给被选中的进程”的过程,即保存和恢复上下文、切换地址空间等操作。
关系
调度决定“谁来上”,切换决定“怎么上”;调度在前,切换在后。

线程的切换过程

线程切换本质是上下文的切换,但比进程切换更轻量,不涉及内存空间的切换。它主要通过保存和恢复 TCB 中的寄存器等执行上下文实现。如果两个线程属于不同进程,还涉及进程的切换;但如果属于同一进程,则只切换线程上下文。

线程切换是指 CPU 从一个线程切换到另一个线程的过程,它涉及的主要是:

  1. 保存当前线程的执行上下文(如寄存器、程序计数器 PC、栈指针 SP)
  2. 更新当前线程的 TCB 状态
  3. 选择另一个线程(调度)
  4. 恢复新线程的上下文
  5. 切换 CPU 执行控制权

上下文信息

线程切换涉及上下文保存,主要包括:

上下文类型
是否保存
说明
程序计数器(PC)
是
指向下一条要执行的指令
栈指针(SP)
是
每个线程有自己的栈
通用寄存器(如 RAX, RBX)
是
保证线程切换时状态一致
程序状态字/标志位
是
比如条件标志(ZF、CF等)
浮点寄存器(FPU 状态)
是(部分架构)
某些平台需额外保存
线程私有变量 / TLS
是
每个线程有独立的 TLS
地址空间(页表等)
否
同一进程的线程共享地址空间,无需切换

进程 vs 线程切换的区别

切换内容
线程切换
进程切换
CPU 寄存器
要保存
要保存
程序计数器
要保存
要保存
栈指针
每线程独立
每进程线程独立
内存空间(页表)
共享
需要切换
TLB 刷新
通常无需
需要刷新
上下文切换成本
低
高
文件描述符/IO资源
共享
独立

进程/线程通信与同步

通信(IPC)方式

进程间通信方式

通信方式
是否跨进程
特点与说明
优点
缺点
管道(Pipe)
✅ 是
半双工,父子进程常用。匿名管道只能用于有亲缘关系的进程。
简单易用,内核提供缓冲;适合轻量通信。
只能单向通信;仅限父子/兄弟进程;缓冲区有限。
命名管道(FIFO)
✅ 是
类似匿名管道,但有名字,可用于无亲缘关系进程。
可以在无亲缘进程间通信;简单。
依然是半双工;数据结构简单。
消息队列(Message Queue)
✅ 是
内核维护消息队列,进程通过发送/接收消息通信。
支持异步通信,结构清晰;适合复杂通信。
内核开销大;消息体长度有限。
共享内存(Shared Memory)
✅ 是
将一段物理内存映射到多个进程虚拟空间中。需结合信号量或锁保证同步。
最高效(无需内核中转);大数据量传输性能优越。
同步控制复杂(需加锁);调试困难。
信号量(Semaphore)
✅ 是
本质是同步机制,用于控制多个进程对共享资源的访问。
控制资源并发访问;常与共享内存搭配使用。
只能用于同步控制;不适合数据通信。
信号(Signal)
✅ 是
操作系统向进程发送异步通知,如 SIGINT 等;可自定义处理函数。
通知机制简单,轻量,适合事件通知。
信息少,只能传递编号;不可控性强,处理麻烦。
套接字(Socket)
✅ 是
支持本地进程间或网络通信,基于 TCP/UDP,可用于不同主机之间。
功能强大;支持远程通信;无亲缘进程可用。
编程复杂;性能不如共享内存。
mmap 映射文件通信
✅ 是
将文件映射到多个进程地址空间中,通过读写文件实现通信。
简单,文件可持久化。
同步依然要靠信号量或锁;不适合高并发。

线程间通信方式

线程属于同一进程,天然共享内存空间,因此通信本质上是「对共享数据的读写」+「同步机制」的组合。

通信方式
特点与说明
优点
缺点
共享变量 + 同步机制
最常见方式,直接访问全局变量或堆上的共享数据,需使用互斥锁、条件变量等控制并发访问。
通信效率极高;无内核参与。
容易发生竞态;同步控制复杂;调试困难。
条件变量(Condition)
与互斥锁配合,支持线程在某个条件不满足时阻塞等待,满足后被唤醒。
支持生产者-消费者模型,逻辑清晰。
使用上较复杂,涉及原子性和死锁问题。
信号量(Semaphore)
支持多线程并发资源控制与同步,POSIX 信号量在线程间也适用。
控制资源并发访问方便;比互斥锁灵活。
容易误用;代码不易维护。
事件(Event)
多用于 Windows 编程,线程可等待事件触发。
使用方便;跨线程同步。
仅限某些平台;实现机制依赖平台。
管道/队列(Queue)
多线程通信框架中常用,如生产者线程写入,消费者线程读取(结合锁)。Python queue.Queue 就是线程安全的。
封装良好,线程安全;支持阻塞/非阻塞。
内部实现依赖锁,仍有上下文切换。
消息传递框架
如 Go 的 channel、Rust 的 mpsc,或 C++ 的消息总线。
更高级抽象,避免显式加锁。
抽象层高,理解成本略高。

总结对比

特性
进程间通信
线程间通信
通信效率
较低(需内核参与)
极高(直接共享内存)
通信复杂度
较复杂(需要多种机制支持)
相对简单(共享变量+锁)
通信安全性
高(内存隔离)
低(需手动同步)
使用场景
不同进程间协作、大量数据传输、网络服务等
同一进程内高并发处理、任务队列、异步事件处理等

进程同步

临界资源

一次仅允许一个进程使用的资源。

同步遵循的准则

  1. 空闲让进:临界区空闲时,可以允许一个请求进入临界区的进程立即进入临界区。
  2. 忙则等待:当已有进程进入临界区时,其他试图进入临界区的进程必须等待。
  3. 有限等待:对请求访问的进程,应保证能在有限时间内进入临界区。
  4. 让权等待:当进程不能进入临界区时,应立即释放处理器,防止进程忙等待。

实现临界区互斥的基本方法

  • 进程同步(Process Synchronization):指的是在多个进程共享资源(如临界资源)时,为了避免竞态条件(Race Condition),需要通过同步机制来协调进程的执行顺序。

  • 互斥(Mutual Exclusion):同步的一个重要目标,确保一次只能有一个进程进入临界区访问共享资源。

分类
方法举例
软件方法
单标志法、双标志法、皮特森算法(Peterson)、Dekker 等
硬件方法
中断屏蔽、TestAndSet、Swap、Compare-And-Swap 等
操作系统原语
信号量(Semaphore)、互斥锁(Mutex)、条件变量等
高级同步机制
管程(Monitor)、消息传递(Message Passing)、信号机制等

软件实现方法

方法
原理说明
特点
单标志法
设置一个公用整型变量 turn,表示允许进入临界区的进程编号。
如:turn=0 则允许 P0 进入。
只能交替使用临界资源,不遵循“空闲让进”,但能保证临界区互斥。
双标志法先检查
每个进程访问临界资源前,先查看对方是否在访问(通过 flag[i])。
flag[i] = TRUE 表示进程 Pi 正在访问临界区。
不遵循“忙则等待”,容易发生两个进程同时进入临界区。
双标志法后检查
先设置自己的 flag[i]=TRUE,再检测对方的 flag[j]。若为 TRUE 则等待。
不遵循“空闲让进”和“有限等待”,可能导致活锁或饥饿。
皮特森算法(Peterson's Algorithm)
设置 flag[i]=TRUE 后再设置 turn=j,表示自己让权给对方。
之后检测对方状态与 turn 标志来决定是否等待。
解决互斥与有限等待问题,但不遵循“让权等待”,仍可能忙等。

锁

基本内容

锁是并发控制机制,用于控制多个线程/进程对共享资源的访问,防止出现竞态条件、数据不一致等问题。

常见锁

  • 互斥锁(Mutex):只能一个线程持有,用于互斥访问资源。
  • 读写锁(RWLock):支持多个读线程并发访问,但写时独占。
  • 自旋锁(Spinlock):忙等待,不释放 CPU,适合锁时间短的场景。它是一种非阻塞的互斥锁,当一个线程尝试获取锁时,如果锁已被其他线程持有,它不会挂起(阻塞)当前线程,而是会在原地不断循环(“自旋”)检查锁是否被释放。
  • 递归锁:同一线程可以多次加锁,不会死锁。
  • 悲观锁 / 乐观锁:见下文。

锁的优缺点

好处

好处
说明
保证数据一致性
多线程访问共享资源时,锁可以防止数据竞争,确保只允许一个线程修改数据。
线程同步机制
锁提供一种通用、直观的方式来管理线程间的同步逻辑。
编程简单
相比无锁编程,使用锁结构清晰、容易理解,便于开发和维护。
多种类型适配不同场景
如互斥锁(mutex)、读写锁、自旋锁、递归锁等可根据性能/粒度选用。

坏处

坏处
说明
容易造成死锁
多线程竞争多个锁,可能形成互相等待,导致系统僵死。
线程阻塞降低性能
阻塞等待会导致线程上下文切换开销增大,浪费 CPU 时间。
可能出现优先级反转
高优先级线程被低优先级线程持有锁而阻塞,影响响应性。
降低并发性
锁粒度过大会使多个线程被串行化,不能充分发挥多核性能。
编程复杂
需要开发者精细设计锁的粒度、范围和顺序,容易出错。

悲观锁 vs 乐观锁

特性
悲观锁(Pessimistic Lock)
乐观锁(Optimistic Lock)
思想
对并发持怀疑态度,总是假设会冲突
对并发持乐观态度,假设不会冲突
实现
加锁机制(如数据库加锁、互斥锁)
不加锁,用版本号 / 时间戳检测冲突
性能
并发低时更安全
并发高时效率更高
适用场景
写多读少,冲突概率大
读多写少,冲突概率小

死锁

概念

死锁(Deadlock) 是指多个进程/线程因争夺资源而造成的一种互相等待的现象,即每个进程都在等待其他进程释放它自己需要的资源,从而导致所有进程都无法继续执行。

导致进程/线程出现错误或者异常的场景除了死锁还有:

  • 饥饿:由长期得不到想要的资源,某进程无法向前推进的现象。
  • 死循环:某进程执行过程中一直跳不出某个循环的现象。

相同点

  • 都是进程无法顺利向前推进的现象(故意设计的死循环除外)。

区别

  • 死锁的发生至少要有两个或两个以上的进程
  • 饥饿的发生可能只有一个进程
  • 死锁和饥饿是管理者(操作系统)的问题,死循环是被管理者(程序逻辑错误,是程序员)的问题

死锁的四个必要条件(同时满足才可能发生死锁)

条件名称
含义说明
互斥
某资源一次只能被一个进程使用。
不剥夺
已分配资源不能被强制剥夺,只能由进程主动释放。
请求并保持
进程已获得部分资源,又请求其他资源但不释放已有资源。
循环等待
存在进程组成的资源等待环,每个进程等待下一个进程所持有的资源。

四个条件必须同时成立才会产生死锁,破坏其中任一即可避免死锁。


死锁的处理策略

策略
核心思想
常见方式
特点说明
预防破坏死锁产生的条件之一
,防患于未然。
禁止循环等待、强制释放资源等
实现简单但资源利用率低。
避免动态检测资源分配是否会进入不安全状态
,若会则不分配资源。
银行家算法(Banker's Algorithm)
性能消耗大,适用于静态系统。
检测与解除允许死锁发生
,通过检测机制发现死锁并强制处理。
周期性检测 + 撤销进程/抢占资源
灵活但代价大,适合容忍一定死锁的系统。

预防死锁

通过破坏死锁的四个必要条件之一或多个来从根本上避免死锁的发生。

  1. 破坏“互斥条件”

    • 尽量使用可共享资源(如只读文件、缓存等),多个进程可同时访问。
    • 但实际很多资源本身无法共享(如写文件、打印机),因此此方法适用范围有限。
  2. 破坏“不可剥夺条件”

    • 如果一个进程请求新资源失败,则主动释放已占资源并等待重试。
    • 系统需支持资源状态保存与恢复,适用于可中断型资源(如内存页、CPU 时间片)。
  3. 破坏“请求并保持条件”

    • 进程在启动时一次性申请所需全部资源,若不能满足则等待所有资源就绪再执行。
    • 降低灵活性,但能有效防止因边申请边持有造成的资源环。
  4. 破坏“循环等待条件”

    • 为所有资源统一编号,进程按照编号升序申请资源,禁止逆序申请。
    • 常用于多线程加锁场景(锁 A → 锁 B,避免锁 B → 锁 A 形成死锁链)。

避免死锁

  1. 破坏“循环等待”

    • 规定所有资源必须按统一顺序申请,防止环形等待。
  2. 破坏“占有且等待”

    • 进程在申请新资源前必须一次性申请完,或先释放已有资源后再申请。
  3. 使用银行家算法

    • 模拟每次资源分配,若发现分配后系统可能进入死锁状态,则拒绝当前请求。
  4. 采用锁顺序规则

    • 多线程程序中,所有线程按照统一顺序加锁。

解除死锁

  1. 终止进程

    • 终止部分或全部死锁相关进程,释放资源,打破循环等待。
    • 可以优先终止低优先级进程或计算开销较小的进程。
  2. 资源剥夺

    • 强制从部分进程中回收资源,使其他进程得以继续执行。
  3. 进程回滚

    • 将某些进程恢复到以前的某个安全状态,重新执行避免死锁。

​

阅读原文:https://mp.weixin.qq.com/s/jPXJwAoAt2lUx3IcItecOg


该文章在 2025/6/19 17:17:24 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-1  粤公网安备44030602007207号