进程同步与互斥的基本概念

一、前提:并发与共享引发的问题

多道程序环境下,进程并发执行,且会访问共享资源(硬件设备、全局变量、缓冲区、文件等)。 多个进程同时读写共享数据时,执行结果不可预期,这种现象称为竞态条件(Race Condition)。 为规避竞态条件、保证数据一致性与执行逻辑正确,引入进程同步与互斥机制。


二、临界区(Critical Section)

1. 定义

进程中访问共享资源的代码片段,是引发竞态条件的根源。 其余不访问共享资源的代码,称为剩余区

2. 临界区使用四大准则(必考)

  1. 空闲让进:临界区无人使用时,允许请求进入的进程立即进入。
  2. 忙则等待:临界区已被占用,其他请求进程必须等待。
  3. 有限等待:等待的进程不能无限阻塞,在有限时间内一定能进入临界区(避免饥饿)。
  4. 让权等待:进程等待时,主动放弃 CPU,不忙等(提升 CPU 利用率)。

补充:忙等(忙等待):进程循环检测临界区状态,一直占用 CPU。


三、进程互斥(Mutual Exclusion)

1. 定义

多个竞争关系的进程,同一时刻最多只能有一个进程进入临界区访问共享资源;一个进程在临界区时,其他进程必须等待。

2. 核心特征

  • 关系:进程间相互竞争共享资源,无固定执行顺序。
  • 目的:保证共享资源的独占访问,杜绝同时操作。
  • 典型场景:独占设备(打印机)、全局变量、账户余额修改。

3. 通俗理解

排他使用,你用我就不能用


四、进程同步(Synchronization)

1. 定义

多个协作关系的进程,按照预先规定的先后次序执行;一个进程的执行依赖另一个进程的运行结果,形成执行顺序约束。

2. 核心特征

  • 关系:进程间相互协作,存在逻辑依赖。
  • 目的:协调执行顺序,保证业务逻辑正确。
  • 典型场景:生产者 - 消费者、数据先写入再读取、流水线任务。

3. 通俗理解

有序执行,你做完,我才能做


五、互斥与同步的区别与联系

1. 核心区别

对比项进程互斥进程同步
进程关系竞争关系,互不依赖协作关系,存在执行依赖
核心要求禁止同时进入临界区保证固定先后执行顺序
访问规则随机竞争,谁先抢到谁执行顺序固定,强制等待前驱进程

2. 联系

  1. 二者都是为了解决并发进程访问共享资源的问题,保障执行正确性。
  2. 同步场景中通常包含互斥:例如生产者 - 消费者,既要控制生产 / 消费顺序(同步),又要独占访问缓冲区(互斥)。
  3. 二者可使用同一套工具实现(信号量、锁等)。

六、两类典型制约关系

从逻辑上划分,并发进程的制约分为两种,对应同步与互斥:

  1. 间接制约(源于资源共享) → 对应互斥 多个进程争抢同一独占资源,相互制约。
  2. 直接制约(源于进程合作) → 对应同步 进程间有数据 / 任务传递,一方执行依赖另一方的结果。

Linux 下的同步与互斥

一、Linux 下的同步互斥 = 3 层结构

操作系统原理 → 内核实现 → 你写代码用的 API

上层:你用的接口(mutex、sem、rwlock、futex)
中层:内核同步原语(信号量、自旋锁、互斥锁、完成量)
下层:硬件原子指令(CAS、atomic、lock 指令)

二、Linux 同步互斥的核心思想

1. 互斥(Mutual Exclusion)

保护共享资源,同一时间只能有一个执行单元访问。

Linux 实现方式:

  • mutex 互斥锁
  • spinlock 自旋锁
  • atomic 原子操作

本质:把多线程并行 → 变成临界区串行。

2. 同步(Synchronization)

让多个进程 / 线程按顺序执行,你做完我再做。

Linux 实现方式:

  • 信号量(semaphore)
  • 条件变量(pthread_cond_t)
  • 完成量(completion)
  • 等待队列(wait queue)

本质:控制执行顺序,解决生产者 - 消费者模型。

三、Linux 最核心的 4 种同步机制(操作系统级)

1)互斥锁(mutex)→ 最常用

Linux 应用层 & 内核层最标准的互斥工具。

原理(操作系统角度)
  • 底层基于 futex(快速用户态互斥锁)
  • 无竞争时:用户态完成,不进内核
  • 有竞争时:阻塞线程,不占 CPU(让权等待)
pthread_mutex_t lock;

pthread_mutex_lock(&lock);    // 进入临界区
临界区代码
pthread_mutex_unlock(&lock);  // 退出临界区
操作系统特点
  • 睡眠等待,不浪费 CPU
  • 临界区可以很长
  • 应用层开发 90% 用这个

2)信号量(semaphore)→ 同步 + 互斥全能

原理
  • 计数器 + 等待队列
  • P 操作(down):申请资源,计数器 - 1
  • V 操作(up):释放资源,计数器 + 1
两种用法
  1. 互斥:sem = 1
  2. 同步:sem = 0 / 资源数

Linux API

sem_t sem;

sem_wait(&sem);    // P
sem_post(&sem);    // V
操作系统定位

信号量 = 通用同步互斥工具 互斥锁是信号量的特例(=1)。

3)自旋锁(spinlock)→ 内核专用

原理
  • 加锁失败时 while 循环忙等待
  • 不睡眠,不切换进程
适用场景
  • 临界区非常短
  • 中断上下文
  • 多核 SMP 环境
特点(操作系统重点)
  • 不睡眠、不调度、不释放 CPU
  • 不能在自旋锁里调用可能阻塞的函数

4)条件变量(condition variable)→ 同步专用

Linux 下实现 “等待 - 唤醒” 最标准工具。

原理
  • 线程可以 主动等待某个条件成立
  • 另一个线程完成后唤醒它
典型模型
  • 生产者 - 消费者
  • 缓冲区空 / 满等待
pthread_mutex_lock(&lock);

while(条件不满足)
    pthread_cond_wait(&cond, &lock);  // 等待并释放锁

// 操作共享资源

pthread_mutex_unlock(&lock);

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐