news 2026/5/8 11:31:43

第5章:并发与竞态条件-16:Bit Operations

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第5章:并发与竞态条件-16:Bit Operations

In continuation of the previous text第5章:并发与竞态条件-15:Atomic Variables, let's GO ahead.

Bit Operations

The atomic_t type is good for performing integer arithmetic. It doesn’t work as well,
however, when you need to manipulate individual bits in an atomic manner. For that
purpose, instead, the kernel offers a set of functions that modify or test single bits
atomically. Because the whole operation happens in a single step, no interrupt (or
other processor) can interfere.

atomic_t类型适用于整数算术运算,但当你需要以原子方式操作单个比特位时,它就不再适用了。针对这类场景,内核提供了一组函数,可原子化地修改或测试单个比特位 —— 由于整个操作在单个步骤中完成,任何中断(或其他处理器)都无法干扰操作过程。

Atomic bit operations are very fast, since they perform the operation using a single
machine instruction without disabling interrupts whenever the underlying platform
can do that. The functions are architecture dependent and are declared in <asm/
bitops.h>. They are guaranteed to be atomic even on SMP computers and are useful
to keep coherence across processors.

原子位操作的执行速度极快:只要底层硬件平台支持,这些操作会通过单条机器指令完成,且无需禁用中断。这类函数与架构强相关,声明在<asm/bitops.h>头文件中;它们能保证在 SMP(对称多处理)系统中仍具备原子性,可有效维持多处理器间的数据一致性。

Unfortunately, data typing in these functions is architecture dependent as well. The
nr argument (describing which bit to manipulate) is usually defined as int but is
unsigned long for a few architectures. The address to be modified is usually a pointer
to unsigned long, but a few architectures use void * instead.

需要注意的是,这些函数的参数类型也与架构相关:

  • nr参数(指定要操作的比特位序号)通常定义为int类型,但部分架构下为unsigned long

  • 待修改数据的地址参数,通常为指向unsigned long的指针,但少数架构中使用void *类型。

The available bit operations are:

// 将addr指向的数据中第nr位设为1 void set_bit(nr, void *addr); /* * 将addr指向的unsigned long类型数据中第nr位清零。 * 其他语义与set_bit一致。 */ void clear_bit(nr, void *addr); // 翻转addr指向数据中第nr位的值(0变1,1变0) void change_bit(nr, void *addr); /* * 该函数是唯一无需原子执行的位操作函数; * 仅返回addr指向数据中第nr位的当前值。 */ test_bit(nr, void *addr); // 原子化设置第nr位,并返回该位操作前的原值 int test_and_set_bit(nr, void *addr); // 原子化清零第nr位,并返回该位操作前的原值 int test_and_clear_bit(nr, void *addr); /* * 原子化翻转第nr位,语义与上述函数一致, * 同时返回该位操作前的原值。 */ int test_and_change_bit(nr, void *addr);

When these functions are used to access and modify a shared flag, you don’t have to
do anything except call them; they perform their operations in an atomic manner.
Using bit operations to manage a lock variable that controls access to a shared vari-
able, on the other hand, is a little more complicated and deserves an example. Most
modern code does not use bit operations in this way, but code like the following still
exists in the kernel.

当使用这些函数访问 / 修改共享标志位时,只需直接调用即可 —— 它们本身已保证操作的原子性。但如果想用位操作实现 “控制共享变量访问的锁”,逻辑会稍复杂,以下是一个示例说明(尽管现代内核代码已很少这样用,但内核中仍存在此类遗留代码)。

A code segment that needs to access a shared data item tries to atomically acquire a
lock using either test_and_set_bit or test_and_clear_bit. The usual implementation is
shown here; it assumes that the lock lives at bit nr of address addr. It also assumes
that the bit is 0 when the lock is free or nonzero when the lock is busy.

若代码段需要访问共享数据,可通过test_and_set_bittest_and_clear_bit原子化获取锁。典型实现逻辑如下:

  • 假设锁对应addr地址的第nr位;

  • 约定:比特位为 0 表示锁空闲,非 0 表示锁被占用。

/* 尝试获取锁 */ while (test_and_set_bit(nr, addr) != 0) wait_for_a_while(); // 锁被占用,等待 /* 执行临界区操作 */ /* 释放锁,并检查状态 */ if (test_and_clear_bit(nr, addr) == 0) something_went_wrong(); // 锁已被释放:出现错误

If you read through the kernel source, you find code that works like this example. It
is, however, far better to use spinlocks in new code; spinlocks are well debugged,

  • they handle issues like interrupts and kernel preemption, and others reading your

code do not have to work to understand what you are doing.

在内核源码中能找到类似上述逻辑的代码,但新代码应优先使用自旋锁而非位操作实现锁机制:自旋锁经过充分调试,能妥善处理中断、内核抢占等问题,且其他开发者阅读代码时,无需额外分析即可理解你的锁逻辑。

补充说明:

1. 原子位操作的核心特性

  • 原子性:操作全程无中断 / 抢占干扰,多 CPU 并发修改同一位时不会出现竞争;

  • 轻量级:无锁的上下文切换 / 自旋开销,仅单条硬件指令(如 x86 的bts/btr指令);

  • 架构兼容性:<asm/bitops.h>会根据 CPU 架构(x86/ARM/RISC-V)封装底层实现,上层代码无需适配。

2. test_bit 非原子性的原因

  • test_bit仅读取位值,不修改数据 —— 即使多 CPU 同时读取同一位,结果也不会出错,因此无需原子化;而set_bit/clear_bit等写操作必须原子化,否则会出现 “读 - 改 - 写” 竞争。

3. 位操作实现锁的缺陷

  • 无抢占 / 中断保护:持有位锁时若发生中断,中断处理程序若也尝试获取该锁,会导致死锁;

  • 无锁排序机制:多把位锁同时获取时,易出现死锁,且无统一的排序规则;

  • 可读性差:需开发者自行约定位的含义,不如自旋锁语义清晰。

4. 原子位操作的正确适用场景

  • 共享标志位:如设备 “忙 / 闲” 状态、中断 “使能 / 禁用” 标记;

  • 位图管理:如内存页分配的位图、设备中断掩码的位操作;

  • 轻量级状态切换:无需完整锁机制的单比特状态修改(如开关类操作)。

5. 现代内核的替代方案

  • 锁机制:优先使用spinlock_t/mutex_t替代位操作实现锁;

  • 标志位管理:仍可使用原子位操作,但仅用于纯状态标记,不用于临界区保护;

  • 多比特操作:若需原子化修改多个比特位,需结合自旋锁 + 普通位操作。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 15:11:48

我发现流式图像滤镜处理慢 后来才知道用WebAssembly SIMD加速

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 目录 我和Node.js的相爱相杀史&#xff1a;一个前端开发者的血泪日记 一、从"前端废物"到全栈咸鱼的蜕变 二、Node.js …

作者头像 李华
网站建设 2026/5/7 19:31:45

基于springboot + vue医院设备管理系统(源码+数据库+文档)

医院设备 目录 基于springboot vue医院设备系统 一、前言 二、系统功能演示 三、技术选型 四、其他项目参考 五、代码参考 六、测试参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 基于springboot vue医院设备系统 一、前言 博主介绍&#xff1a;✌️大…

作者头像 李华
网站建设 2026/5/7 19:31:44

【dz-954】基于单片机的热水器设计

摘要 随着人们生活品质的提升&#xff0c;热水器作为家庭必备电器&#xff0c;其安全、节能与智能化运行愈发受到重视。传统热水器存在水温控制精度低、水位监测滞后、能源利用效率不高等问题&#xff0c;依赖人工操作易导致资源浪费或使用不便&#xff0c;难以满足现代家庭对…

作者头像 李华
网站建设 2026/5/7 19:31:44

【dz-959】基于嵌入式的GPS定位系统和智能语音播报系统设计

摘 要 在现代社会&#xff0c;随着物联网技术的飞速发展&#xff0c;人们对实时定位和信息交互的需求日益增长。传统的定位系统往往只能提供单一的视觉信息&#xff0c;缺乏直观的交互体验。因此&#xff0c;设计一种集成了定位与语音交互功能的嵌入式系统具有重要的现实意义。…

作者头像 李华