1. 并发控制基础:并发编程概念、竞态条件、临界区、原子操作概述

在嵌入式 Linux 驱动开发中,并发控制是保障系统稳定性和数据一致性的基石。本章节从最基础的并发编程概念出发,逐步剖析竞态条件的成因、临界区的划定原则,以及原子操作这一最底层的同步原语。理解这些基础概念,是后续学习 RCU(Read-Copy-Update)等高级同步机制的前提。

1.1 并发编程核心概念

并发(Concurrency)是指多个执行单元在宏观上同时推进的执行方式。在嵌入式 Linux 系统中,并发来源主要包括:

  • 对称多处理(SMP):多个 CPU 核心同时执行内核代码。
  • 中断与底半部:硬件中断、软中断、tasklet、工作队列等异步执行路径。
  • 内核抢占:高优先级进程抢占低优先级进程的执行。
  • 进程与线程:多个用户态进程或内核线程共享资源。
关键认知: 并发 ≠ 并行。并发是逻辑上的同时执行(单核时间片轮转也可实现),并行是物理上的同时执行(多核)。驱动开发者需要同时应对这两种情况。

1.2 竞态条件(Race Condition)

竞态条件是指多个执行单元对共享资源进行非原子访问时,最终结果依赖于执行顺序的不可预测性。竞态条件通常导致数据损坏、系统崩溃或安全漏洞。

竞态类型 典型场景 后果
读-写竞态 一个线程读取共享变量,同时另一个线程写入 读取到不一致的中间值
写-写竞态 两个线程同时写入同一共享变量 最终值取决于写入顺序,可能丢失更新
检查-使用竞态 先检查条件再使用资源,但条件在检查后改变 使用已释放或无效的资源
驱动开发警示: 竞态条件在单核非抢占系统也可能发生(如中断与进程上下文之间)。不要假设“单核无竞态”。

1.3 临界区(Critical Section)

临界区是指访问共享资源的代码片段,在同一时刻只允许一个执行单元进入。临界区的划定直接影响并发控制的粒度与性能。

临界区设计原则:

  1. 最小化原则:临界区应只包含必要的共享资源访问代码,避免无关操作。
  2. 不可嵌套过度:避免在临界区内调用可能引起阻塞或调度的函数。
  3. 明确边界:清晰标记临界区的入口与出口,防止遗漏。
并发控制基础概念关系图 并发控制基础概念关系图 SMP 多核 中断/底半部 内核抢占 进程/线程 竞态条件 临界区 同步机制:原子操作 → 自旋锁 → 互斥锁 → RCU 核心逻辑 并发来源 → 竞态 → 划定临界区 → 选择同步机制

1.4 原子操作(Atomic Operation)

原子操作是不可被中断的单一操作,要么全部执行完成,要么完全不执行。在 Linux 内核中,原子操作是构建所有高级同步机制的基础砖块。

1.4.1 原子操作分类

类型 API 示例 说明
原子整数操作 atomic_t / atomic_inc() / atomic_dec_and_test() 对 32 位整数的原子加减、测试
原子位操作 set_bit() / clear_bit() / test_and_set_bit() 对内存中某一位的原子置位、清除、测试
原子长整型操作 atomic64_t / atomic64_add() 64 位架构下的原子操作(ARM64、x86_64)

1.4.2 原子操作使用示例

#include <linux/atomic.h>

static atomic_t usage_count = ATOMIC_INIT(0);

/* 驱动打开时原子递增 */
int driver_open(struct inode *inode, struct file *filp) {
    if (!atomic_add_unless(&usage_count, 1, MAX_USERS))
        return -EBUSY;
    return 0;
}

/* 驱动关闭时原子递减 */
int driver_release(struct inode *inode, struct file *filp) {
    atomic_dec(&usage_count);
    return 0;
}
原子操作优势: 无锁、无阻塞、无上下文切换开销,适用于简单的计数器、标志位、引用计数等场景。但原子操作无法解决复杂的资源保护问题(如链表遍历与修改)。

1.5 并发控制层次结构

从原子操作到 RCU,Linux 内核提供了一套层次化的并发控制机制。理解各层次的适用场景和性能特征,是驱动开发者的核心能力。

Linux 内核并发控制层次结构 Linux 内核并发控制层次结构 底层:原子操作(atomic_t / bitops / atomic64_t) 中间层:锁机制 自旋锁(spinlock) 互斥锁(mutex) 读写锁(rwlock) 信号量 上层:高级同步机制(RCU / 完成量 / 顺序锁) 层次递进:原子操作提供硬件级保证 → 锁机制提供互斥访问 → 高级机制提供特定场景优化(如 RCU 读多写少)

1.6 本章小结

  • 并发来源:SMP、中断、抢占、多进程/线程是嵌入式 Linux 驱动的四大并发源头。
  • 竞态条件:当多个执行单元无序访问共享资源时产生,是驱动 bug 的主要来源。
  • 临界区:保护共享资源的代码段,应遵循最小化原则。
  • 原子操作:最底层的同步原语,适用于简单计数和标志位保护,是构建锁和 RCU 的基础。