Jorgen's blog Jorgen's blog
首页
  • 平台架构
  • 混合式开发记录
  • 推送服务
  • 数据分析
  • 实时调度
  • 架构思想

    • 分布式
  • 编程框架工具

    • 编程语言
    • 框架
    • 开发工具
  • 数据存储与处理

    • 数据库
    • 大数据
  • 消息、缓存与搜索

    • 消息队列
    • 搜索与日志分析
  • 前端与跨端开发

    • 前端技术
    • Android
  • 系统与运维

    • 操作系统
    • 容器化与 DevOps
  • 物联网与安全

    • 通信协议
    • 安全
    • 云平台
newland
  • 关于我
  • 终身学习
  • 关于时间的感悟
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

jorgen

Love it, make mistakes, learn, keep grinding.
首页
  • 平台架构
  • 混合式开发记录
  • 推送服务
  • 数据分析
  • 实时调度
  • 架构思想

    • 分布式
  • 编程框架工具

    • 编程语言
    • 框架
    • 开发工具
  • 数据存储与处理

    • 数据库
    • 大数据
  • 消息、缓存与搜索

    • 消息队列
    • 搜索与日志分析
  • 前端与跨端开发

    • 前端技术
    • Android
  • 系统与运维

    • 操作系统
    • 容器化与 DevOps
  • 物联网与安全

    • 通信协议
    • 安全
    • 云平台
newland
  • 关于我
  • 终身学习
  • 关于时间的感悟
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 计算机系统漫游
  • 进程与线程:操作系统的核心调度单元
  • 12.内存管理-操作系统的资源分配大师
  • 16.内存管理-操作系统的资源分配艺术
  • 内存管理-操作系统的核心资源分配
  • 内存管理-操作系统的核心资源分配器
  • 内存管理-操作系统的核心资源分配机制
  • 内存管理:操作系统的核心资源调度
  • 内存管理:操作系统的资源分配大师
  • 内存管理 - 操作系统的资源分配核心
  • 内存管理:操作系统的资源分配艺术
  • 文件系统与I/O管理-操作系统的数据持久化桥梁
  • 设备管理-操作系统的硬件交互之门
  • 进程间通信-操作系统的对话桥梁
  • 操作系统安全与保护-数字世界的守护者
  • 调度算法-操作系统的指挥棒
  • 死锁-操作系统的资源竞争困境
  • 系统调用-应用程序与操作系统的对话桥梁
  • 虚拟化技术-操作系统的资源抽象魔法
  • 实时操作系统-时间的守护者
  • 并发控制-操作系统的协同艺术
    • 前言
    • 并发的基本概念
      • 为什么需要并发控制?
    • 并发控制机制
      • 1. 临界区与互斥锁
      • 2. 信号量
      • 3. 条件变量
      • 4. 读写锁
      • 5. 管道与消息队列
      • 6. 共享内存
    • 并发控制的挑战
    • 现代操作系统中的并发控制
    • 结语
  • 中断处理-操作系统的生命线
  • 分布式操作系统-跨越多机的资源协调大师
  • 操作系统启动过程-从按下电源键到可用的奇妙旅程
  • 页面置换算法-操作系统的内存魔术师
  • operating_system
Jorgen
2026-01-28
目录

并发控制-操作系统的协同艺术

# 前言

在现代计算机系统中,多任务处理和多道程序设计已经成为常态。操作系统作为计算机系统的核心软件,必须有效地管理和协调多个进程/线程的执行,以确保系统的稳定性和高效性。并发控制机制正是操作系统实现这一目标的关键技术。

# 并发的基本概念

并发(Concurrency)是指两个或多个事件在同一时间间隔内发生。在操作系统中,并发表现为多个进程或线程同时执行,但实际上它们可能是在不同的处理器上并行执行,或者是在单个处理器上通过时间片轮转交替执行。

# 为什么需要并发控制?

在多进程/多线程环境下,多个执行流可能会访问共享资源,如内存、文件、设备等。如果没有适当的控制机制,可能会导致以下问题:

  1. 竞争条件(Race Condition):多个进程/线程同时访问和修改共享数据,导致不可预测的结果。
  2. 数据不一致:共享数据可能处于不一致的状态。
  3. 死锁(Deadlock):多个进程/线程互相等待对方释放资源,导致所有进程/线程都无法继续执行。
  4. 饥饿(Starvation):某些进程/线程长时间无法获得所需的资源。

# 并发控制机制

操作系统提供了多种并发控制机制,以确保多进程/多线程环境下的正确性和高效性。

# 1. 临界区与互斥锁

临界区(Critical Section)是指访问共享资源的代码段,在同一时间只能被一个进程/线程执行。互斥锁(Mutex, Mutual Exclusion)是实现临界区控制的基本机制。

// 伪代码示例
mutex_init(&mutex);  // 初始化互斥锁

process1() {
    mutex_lock(&mutex);  // 加锁
    // 临界区代码
    shared_resource++;
    mutex_unlock(&mutex);  // 解锁
}

process2() {
    mutex_lock(&mutex);  // 加锁
    // 临界区代码
    shared_resource--;
    mutex_unlock(&mutex);  // 解锁
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

互斥锁确保了同一时间只有一个进程/线程能够进入临界区,从而避免了竞争条件。

# 2. 信号量

信号量(Semaphore)是由Dijkstra提出的一种更通用的同步机制。信号量是一个整型变量,除了初始化外,只能通过两个原子操作来访问:P操作(等待)和V操作(释放)。

// 伪代码示例
semaphore_init(&sem, 1);  // 初始化信号量为1

process1() {
    P(&sem);  // 等待信号量
    // 临界区代码
    shared_resource++;
    V(&sem);  // 释放信号量
}

process2() {
    P(&sem);  // 等待信号量
    // 临界区代码
    shared_resource--;
    V(&sem);  // 释放信号量
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

信号量不仅可以用于实现互斥,还可以用于控制多个进程/线程对有限资源的访问。

# 3. 条件变量

条件变量(Condition Variable)通常与互斥锁一起使用,允许线程在某个条件不满足时等待,并在条件满足时被通知。

// 伪代码示例
mutex_init(&mutex);
cond_init(&cond);

process1() {
    mutex_lock(&mutex);
    while (!condition_met) {
        cond_wait(&cond, &mutex);  // 等待条件变量,自动释放互斥锁
    }
    // 临界区代码
    mutex_unlock(&mutex);
}

process2() {
    mutex_lock(&mutex);
    // 修改条件
    condition_met = true;
    cond_signal(&cond);  // 通知等待的线程
    mutex_unlock(&mutex);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

条件变量提供了一种高效的方式,让线程在条件不满足时避免忙等待(Busy Waiting)。

# 4. 读写锁

读写锁(Read-Write Lock)是一种特殊的锁,允许多个读线程同时访问共享资源,但写线程必须独占访问。

// 伪代码示例
rwlock_init(&rwlock);

reader() {
    rwlock_read_lock(&rwlock);
    // 读取共享资源
    rwlock_unlock(&rwlock);
}

writer() {
    rwlock_write_lock(&rwlock);
    // 修改共享资源
    rwlock_unlock(&rwlock);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

读写锁适用于读操作远多于写操作的场景,可以显著提高并发性能。

# 5. 管道与消息队列

管道(Pipe)和消息队列(Message Queue)是进程间通信(IPC)的机制,也常用于并发控制。

管道是一种半双工的通信方式,数据只能单向流动。消息队列则允许进程/线程以消息的形式交换数据。

// 伪代码示例:使用管道进行进程间通信
int pipefd[2];
pipe(pipefd);  // 创建管道

if (fork() == 0) {  // 子进程
    close(pipefd[0]);  // 关闭读端
    write(pipefd[1], "Hello, Parent!", 14);  // 向父进程发送消息
    close(pipefd[1]);
} else {  // 父进程
    close(pipefd[1]);  // 关闭写端
    char buffer[14];
    read(pipefd[0], buffer, 14);  // 从子进程接收消息
    close(pipefd[0]);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 6. 共享内存

共享内存(Shared Memory)是一种高效的IPC机制,允许多个进程访问同一块物理内存区域。

// 伪代码示例:使用共享内存
int shm_id = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0666);  // 创建共享内存
char *shm_ptr = (char *)shmat(shm_id, NULL, 0);  // 附接到进程地址空间

// 进程1写入数据
strcpy(shm_ptr, "Hello, Process 2!");

// 进程2读取数据
printf("Received: %s\n", shm_ptr);

// 分离共享内存
shmdt(shm_ptr);
1
2
3
4
5
6
7
8
9
10
11
12

# 并发控制的挑战

实现有效的并发控制面临诸多挑战:

  1. 死锁:多个进程/线程互相等待对方释放资源,导致所有进程/线程都无法继续执行。
  2. 饥饿:某些进程/线程长时间无法获得所需的资源。
  3. 优先级反转:低优先级进程持有高优先级进程所需的资源,导致高优先级进程被阻塞。
  4. 上下文切换开销:频繁的线程/进程切换会带来额外的性能开销。

# 现代操作系统中的并发控制

现代操作系统采用了更先进的并发控制技术:

  1. 无锁数据结构:使用原子操作(如CAS, Compare-And-Swap)实现无锁并发控制,减少锁竞争。
  2. 读写锁的优化:如读写锁的升级和降级、分段锁等。
  3. 自适应自旋锁:在短时间等待时使用自旋,长时间等待时让出CPU。
  4. NUMA感知的锁:考虑非一致性内存访问(NUMA)架构的锁优化。

# 结语

并发控制是操作系统的核心功能之一,它确保了多进程/多线程环境下的正确性和高效性。从简单的互斥锁到复杂的无锁数据结构,操作系统提供了丰富的并发控制机制来满足不同场景的需求。

随着多核处理器和分布式系统的普及,并发控制技术将继续发展和演进,为构建高性能、高可靠性的计算机系统提供坚实的基础。

"并发不是关于速度,而是关于正确性。" — Rob Pike

#操作系统#并发控制#同步机制
上次更新: 2026/01/28, 15:09:46
实时操作系统-时间的守护者
中断处理-操作系统的生命线

← 实时操作系统-时间的守护者 中断处理-操作系统的生命线→

最近更新
01
LLM
01-30
02
intro
01-30
03
intro
01-30
更多文章>
Theme by Vdoing | Copyright © 2019-2026 Jorgen | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式