进程与同步

从进程/线程并发执行,到同步互斥,再到死锁处理的完整知识主干。

一句话模型

进程拥有资源、线程执行代码;多个执行流共享资源时需要同步和互斥来约束执行顺序,若资源分配形成循环等待,就会进入死锁,需要通过预防、避免或检测解除来处理。

三层递进

  1. 简单:区分进程、线程、资源和调度状态,建立并发执行的参与者模型。
  2. 中等:从临界区出发,连接互斥锁、信号量、条件变量和生产者/消费者流程。
  3. 复杂:把资源分配图、死锁四个必要条件、银行家算法和检测解除策略叠加起来。

简单图谱:进程与线程

进程主要解决“资源归谁所有”,线程主要解决“由谁执行代码”。PCB 保存进程级资源和状态,线程控制块保存各执行流的寄存器、PC、栈和调度状态。

ProcessSyncSimpleMapprogram程序静态代码与数据process进程资源分配与保护program->process加载运行thread线程执行与调度process->thread包含一个或多个pcbPCB地址空间 / 文件 / 状态process->pcbtcbTCBPC / 寄存器 / 栈thread->tcbshared共享资源内存 / 文件 / 设备thread->shared并发访问risk竞态条件执行交错导致不一致shared->risk
# 进程与同步

## 并发执行主体

- 程序:静态指令和数据
- 进程:程序的一次执行,资源分配基本单位
- 线程:进程内的执行流,调度基本单位
- PCB / TCB:保存管理信息和处理机现场

## 共享状态

- 进程地址空间与打开文件
- 线程共享进程资源
- 临界资源与临界区

## 风险

- 竞态条件:结果依赖执行交错
- 不一致:复合操作被切换打断
- 资源等待:可能导致死锁

基础知识页面:进程和线程进程管理

中等图谱:同步与互斥

主干问题是:多个执行流同时访问共享资源时,如何保证结果正确,并在需要时建立先后顺序?

ProcessSyncFlowMapnoncritical非临界区准备数据acquireLock / P(wait)获取互斥或许可noncritical->acquirecritical临界区访问共享资源acquire->critical获得锁/许可other其他线程阻塞或继续执行acquire->other不可获得:阻塞condition条件不满足?条件变量等待critical->conditionreleaseUnlock / V(signal)释放并唤醒release->other唤醒等待者condition->critical否:继续condition->release是:完成操作

一次临界区访问可以这样追踪:线程先执行非临界区;进入临界区前获取锁或执行 P/wait;获得许可后访问共享资源;离开临界区时解锁或执行 V/signal,唤醒等待者。

  • 互斥约束“同一时刻最多一个执行流进入临界区”。
  • 同步约束“多个执行流之间满足某种先后关系”,例如消费者必须等待缓冲区非空。
  • 信号量既能实现互斥锁,也能用计数表示可用资源数量。
  • 条件变量通常与互斥锁配合,等待条件不满足时释放锁并阻塞。

复杂图谱:资源等待与死锁

死锁不是普通的阻塞,而是多个进程互相等待、任何一个都无法继续推进的闭环。复杂图把同步原语造成的资源占用,连接到死锁的检测和处理策略。

ProcessSyncDeadlockMapacquire进程申请资源hold占有已分配资源等待其他资源acquire->holdresource资源分配图进程 → 资源:请求资源 → 进程:占有hold->resourcecycle四条件同时成立?互斥 / 占有并等待非抢占 / 循环等待resource->cycledeadlock死锁进程互相等待,无法推进cycle->deadlocknormal继续执行并释放资源cycle->normalprevent预防破坏任一必要条件deadlock->preventavoid避免安全性检查 / 银行家算法deadlock->avoiddetect检测与解除发现环、抢占/终止/回滚deadlock->detect

阅读时沿三条路径追踪:

  • 正常路径:申请资源 → 获得资源 → 执行 → 释放资源。
  • 死锁形成路径:互斥 + 占有并等待 + 非抢占 + 循环等待同时成立。
  • 处理路径:预防破坏必要条件;避免在分配前做安全性检查;检测发现环后解除或回收资源。

子模块图谱:同步原语

同步原语的差异可以归结为“保护什么状态、阻塞在哪里、由谁唤醒”。互斥锁保护临界区,信号量管理许可或资源计数,条件变量等待谓词成立。

SynchronizationPrimitiveMapproblem并发访问共享状态mutex互斥锁一个持有者Lock / Unlockproblem->mutex排他访问sem信号量许可计数P(wait) / V(signal)problem->sem资源数量 / 同步cond条件变量等待谓词成立Wait / Signalproblem->cond条件等待atomic原子指令CAS / Test-and-Setmutex->atomic底层实现critical安全访问临界资源mutex->criticalsem->criticalorder建立执行顺序生产者先放入,消费者后取出sem->ordercond->order

子模块图谱:死锁处理

死锁处理策略对应不同的系统取舍:预防限制并发资源申请,避免需要知道最大需求并运行银行家算法,检测解除则允许风险发生后再恢复。

DeadlockStrategyMapstate资源分配状态prevent死锁预防限制申请顺序或方式破坏必要条件state->preventavoid死锁避免预分配试探安全序列检查state->avoiddetect检测与解除允许风险发生发现后恢复state->detectsafe安全状态存在完成所有进程的序列avoid->safe通过检查unsafe不安全 / 死锁状态avoid->unsafe拒绝分配detect->unsafe检测到环unsafe->detect抢占、终止或回滚

基础知识页面:同步和互斥死锁

关键问题

进程和线程为什么要分成两个抽象?

进程隔离地址空间和系统资源,线程共享进程资源并承担执行与调度;这样既能保护资源,又能在同一进程内低成本并发。

同步和互斥有什么区别?

互斥是排他访问,回答“谁能进入临界区”;同步是执行顺序约束,回答“谁应该先做、谁需要等待”。一个同步问题可以同时包含互斥和条件等待。

为什么加锁后仍然可能死锁?

锁只保证单个临界区的互斥,不自动保证多个锁的申请顺序。如果线程 A 持有锁 1 等锁 2,线程 B 持有锁 2 等锁 1,就形成循环等待。

银行家算法检查的是什么?

它检查的是“试探性分配后是否仍存在安全序列”,不是判断当前是否已经死锁。安全状态表示存在一个顺序,使所有进程都能获得剩余资源并完成。

旁路清单

  • 进程状态:创建、就绪、运行、阻塞、终止与状态转换
  • 线程实现:用户级线程、内核级线程和多线程模型
  • 同步实现:禁用中断、原子指令、自旋锁、互斥锁、信号量
  • 经典问题:生产者/消费者、读者/写者、哲学家进餐
  • 死锁模型:资源分配图、可达性、安全序列和安全性检查
  • 死锁解除:抢占资源、终止进程、回滚和重新分配

对应页面:进程和线程同步和互斥死锁