- 人工智能
- AI 技能
- 文档
- 开发工具
【免费下载链接】DocAgent
AtomicBool是仓颉标准库std.sync包中面向Bool类型的原子操作类,用于在多线程共享变量的场景下提供无锁、线程安全的读写与比较交换能力。本文以其官方 API 文档为主体,结合仓库内的包级说明与可验证示例,系统讲解构造、load/store/swap/compareAndSwap四大类操作的语义、内存排序机制与弃用 API 的迁移方式,帮助读者在仓颉并发编程中正确、高效地使用布尔原子变量。
一、背景:为什么需要AtomicBool
随着多核处理器普及,并发编程成为发挥多核优势的关键。仓颉语言提供spawn关键字创建用户态轻量级线程(M:N 线程模型),当多个线程同时访问同一个共享变量时,普通的读写在多线程下会产生数据竞争。
std.sync包(sync_package_overview.md)为此提供了一整套并发原语,其中原子操作是其中最轻量、最基础的机制,包括:
- 8 种整数类型的原子操作:
AtomicInt8/16/32/64、AtomicUInt8/16/32/64; - Bool 类型原子操作
AtomicBool(本文主角); - 引用类型原子操作
AtomicReference<T>与AtomicOptionReference<T>。
与整数原子类型不同,Bool类型和引用类型的原子操作只提供读、写和交换操作,不提供fetchAdd等算术运算(见 sync_package_overview.md)。这符合布尔值的语义:它只有true/false两个状态,最典型的用途是作为多线程间的开关标志、状态位或条件变量配套的等待标志。
二、类声明与功能总览
从 sync_package_classes.md 可知,AtomicBool的完整声明为:
public class AtomicBool { public init(val: Bool) }其功能为:提供Bool类型的原子操作相关函数,内部封装一个Bool值,对该值的所有操作均以原子方式进行,无需加锁即可保证多线程下的可见性与一致性。
成员函数速查表
| 函数 | 原型 | 核心语义 |
|---|---|---|
| init | (val: Bool) | 构造实例,内部值初始化为val |
| compareAndSwap | (old: Bool, new: Bool): Bool | CAS 比较交换,返回是否成功 |
| compareAndSwap | (old, new, successOrder!, failureOrder!): Bool | 指定内存排序的 CAS(已弃用) |
| load | (): Bool | 读取当前值 |
| load | (memoryOrder!): Bool | 指定内存排序的读取(已弃用) |
| store | (val: Bool): Unit | 写入新值 |
| store | (val, memoryOrder!): Unit | 指定内存排序的写入(已弃用) |
| swap | (val: Bool): Bool | 写入新值并返回写入前的旧值 |
| swap | (val, memoryOrder!): Bool | 指定内存排序的交换(已弃用) |
下面逐一对每类操作展开说明。
三、构造函数:初始化原子布尔值
public init(val: Bool)构造一个封装Bool数据类型的AtomicBool实例,其内部数据的初始值为入参val的值。参数说明:
val: Bool:原子类型的初始值。
AtomicBool没有无参构造函数,创建时必须显式指定初始值。例如:
import std.sync.AtomicBool let flag = AtomicBool(true) // 初始值为 true let off = AtomicBool(false) // 初始值为 false从仓库示例 sync_samples.md 可以看到,AtomicBool(true)这种"默认开启"的初始化方式,常与条件变量配合实现线程挂起与唤醒。
四、读取操作 load
默认形式
public func load(): Bool读取操作,采用默认内存排序方式,读取原子类型的值,返回当前Bool值。
弃用的指定内存排序形式
public func load(memoryOrder!: MemoryOrder): Bool读取操作,采用参数memoryOrder指定的内存排序方式读取原子类型的值。
注意:该重载未来版本即将废弃,请使用
load()替代(见 sync_package_classes.md)。
使用要点
load是最常用的读取手段。在多线程环境下,不应直接读取被多个线程修改的普通Bool变量,而应通过load()获取,以保证读到的是最新且一致的值。例如判断"开关是否已关闭":
if (!flag.load()) { // 开关已关闭,执行退出逻辑 }五、写入操作 store
默认形式
public func store(val: Bool): Unit写入操作,采用默认内存排序方式,将参数val指定的值写入原子类型。参数val: Bool为写入原子类型的值。
弃用的指定内存排序形式
public func store(val: Bool, memoryOrder!: MemoryOrder): Unit写入操作,采用参数memoryOrder指定的内存排序方式将val写入原子类型。
注意:该重载未来版本即将废弃,请使用
store(Bool)替代(见 sync_package_classes.md)。
使用要点
store与load成对出现,用于更新共享的布尔状态。在仓库的 Condition 示例 中,主线程正是通过flag.store(false)将原子布尔标志置为false,从而通知挂起中的子线程可以继续执行:
import std.sync.{Mutex, Condition, AtomicBool} var mutex = Mutex() var flag = AtomicBool(true) main(): Int64 { let condition: Condition synchronized(mutex) { condition = mutex.condition() // 在持有锁的情况下生成 Condition 实例 } let fut = spawn { synchronized(mutex) { println("New thread: before wait") condition.waitUntil {=> !flag.load() } // 挂起,直到 flag 为 false println("New thread: after wait") } } /* 睡眠 10 毫秒,以确保新线程可以执行 */ sleep(10 * Duration.millisecond) synchronized(mutex) { println("Main thread: set flag") flag.store(false) // 修改 flag 值,唤醒条件满足 println("Main thread: notify") condition.notifyAll() // 唤醒等待中的子线程 } /* 等待新线程完成 */ fut.get() return 0 }该示例的运行结果(与 sync_samples.md 中验证输出一致):
New thread: before wait Main thread: set flag Main thread: notify New thread: after wait这个例子完整展示了load/store在"共享标志位"场景下的典型用法:子线程循环load()轮询标志,主线程通过store()修改标志,配合Condition完成跨线程的信号通知。
六、交换操作 swap
默认形式
public func swap(val: Bool): Bool交换操作,采用默认内存排序方式,将参数val指定的值写入原子类型,并返回写入前的值。
弃用的指定内存排序形式
public func swap(val: Bool, memoryOrder!: MemoryOrder): Bool交换操作,采用参数memoryOrder指定的内存排序方式写入val,并返回写入前的值。
注意:该重载未来版本即将废弃,请使用
swap(Bool)替代(见 sync_package_classes.md)。
使用要点
swap的关键特征是"读写一体、返回旧值"。这一点与整数原子类型的fetchAdd/fetchSub等操作一致——交换操作和算术操作的返回值都是修改前的值(见 sync_package_overview.md)。
swap适合"先取旧值、再置新值"的原子复合操作,例如多线程互斥抢一个标志位:
// 若返回 false,说明之前没有人占用,本线程成功抢到标志 let previous = occupied.swap(true) if (!previous) { // 成功抢到独占权 } else { // 已被其他线程占用 }这个模式常被称为"原子测试并置位"(test-and-set),无需加锁即可实现轻量级互斥语义。
七、CAS 比较交换 compareAndSwap
默认形式
public func compareAndSwap(old: Bool, new: Bool): BoolCAS(Compare and Swap)操作,采用默认内存排序方式。比较当前原子类型的值与参数old指定的值是否相等:
- 若相等:写入参数
new指定的值,并返回true; - 否则:不写入任何值,并返回
false。
参数说明:
old: Bool:与当前原子类型进行比较的值;new: Bool:比较结果相等时写入原子类型的值;- 返回值
Bool:交换成功返回true,失败返回false。
弃用的指定内存排序形式
public func compareAndSwap(old: Bool, new: Bool, successOrder!: MemoryOrder, failureOrder!: MemoryOrder): BoolCAS 操作,成功时使用successOrder指定的内存排序方式,失败时使用failureOrder指定的内存排序方式:
successOrder!: MemoryOrder:CAS 操作成功时,执行"读 → 修改 → 写"操作需要的内存排序方式;failureOrder!: MemoryOrder:CAS 操作失败时,执行"读"操作需要的内存排序方式。
注意:该重载未来版本即将废弃,请使用
compareAndSwap(Bool, Bool)替代(见 sync_package_classes.md)。
CAS 的典型应用
CAS 是构建无锁算法的基石。它的语义可以概括为"只有当前值与预期一致时才更新",天然防止了并发下的覆盖写。例如实现"仅当标志为 false 时才置为 true"的一次性初始化:
// 只有当前值为 false 时才写入 true;若已被其他线程置位则失败 if (initialized.compareAndSwap(false, true)) { // 本线程成功完成一次性初始化 } else { // 其他线程已完成初始化 }值得注意的是,虽然 CAS 对Bool只有两个取值(true/false)看似简单,但它的语义保证——比较与写入是一个不可分割的原子步骤——使得多个线程并发调用时不会出现"同时写入"的竞态。
八、内存排序:默认排序与 MemoryOrder
AtomicBool文档中反复出现的"默认内存排序方式",对应的是std.sync包中的常量 DefaultMemoryOrder:
public let DefaultMemoryOrder: MemoryOrder = MemoryOrder.SeqCst其类型为枚举 MemoryOrder:
public enum MemoryOrder { | SeqCst }内存顺序的背景:出于性能优化考虑,编译器或 CPU 可能对指令进行重新排序,内存顺序枚举即用来表示排序策略。SeqCst(顺序一致)表示禁止指令重排,确保该原子操作之前的所有原子操作都先于该操作之后的原子操作完成。
DefaultMemoryOrder与带MemoryOrder参数的各重载(load/store/swap/compareAndSwap)均已标记为未来版本即将废弃,同时MemoryOrder枚举本身也标注 deprecated。因此:
- 新代码应直接使用无内存排序参数的默认重载,即
load()、store(val)、swap(val)、compareAndSwap(old, new); - 迁移路径明确:
load(memoryOrder!)→load(),store(val, memoryOrder!)→store(val),swap(val, memoryOrder!)→swap(val),compareAndSwap(old, new, successOrder!, failureOrder!)→compareAndSwap(old, new)。
默认实现即采用顺序一致的强排序,足以覆盖绝大多数共享标志位场景,这也是官方将这些参数化重载逐步淘汰的原因。
九、实战综合示例:多线程安全的状态切换
结合上述全部 API,给出一个将AtomicBool用作线程间共享开关的完整可运行示例(风格参照 sync_samples.md 中经过 verify 验证的代码):
import std.sync.AtomicBool import std.time.* let running = AtomicBool(true) // 全局运行开关 main(): Int64 { // 工作线程:轮询开关 let worker = spawn { while (running.load()) { // 执行工作... sleep(Duration.millisecond) } println("worker: 开关已关闭,退出") } // 主线程:运行一段时间后原子地关闭开关 sleep(Duration.second) running.store(false) // 原子写入 println("main: 已置位关闭开关") worker.get() return 0 }示例要点回顾:
AtomicBool(true)初始化开关为开启状态;- 工作线程通过
load()安全读取状态; - 主线程通过
store(false)原子关闭开关,无需加锁; - 若需要"取旧值并置新值",改用
swap; - 若需要"仅当符合预期才更新",改用
compareAndSwap。
十、使用建议与注意事项
综合 AtomicBool_class.md、sync_package_overview.md 与 sync_samples.md,给出如下实践建议:
- Bool 原子类型无算术操作:
AtomicBool只提供load/store/swap/compareAndSwap,若需要计数类操作(如fetchAdd),应改用AtomicInt8/16/32/64或AtomicUInt8/16/32/64等整数原子类型; swap与fetchAdd等操作返回修改前的值,设计判断逻辑时注意返回值语义,勿混淆"新值"与"旧值";- CAS 返回的是"是否成功":
compareAndSwap返回Bool表示交换是否发生,若要获取旧值需先load()或在循环中结合读取使用; - 避免使用已弃用的
MemoryOrder重载:未来版本将移除,应迁移到默认内存排序的无参/无排序版本; - 原子变量不等于完全免锁:当多个变量需要作为整体保持一致性(如本例中
flag与Condition的配合)时,仍需结合synchronized与 Lock 等机制保证原子性。
十一、总结
AtomicBool是仓颉std.sync包中面向布尔共享变量的原子操作类,通过init构造、load读取、store写入、swap交换、compareAndSwap比较交换五组 API,在多线程环境下提供无锁的线程安全访问。其默认采用顺序一致(SeqCst)的内存排序,而带MemoryOrder参数的旧重载均已弃用。掌握这些 API 的语义差异(尤其是返回值含义)与适用场景,即可在仓颉并发程序中安全地实现开关标志、一次性初始化、轻量级互斥等常见同步需求。更多原子类型(整数、引用类型)与线程同步机制(Mutex、Condition、Barrier、Semaphore等)可继续参阅 std.sync readme 与 sync 包概览。
- 人工智能
- AI 技能
- 文档
- 开发工具
【免费下载链接】DocAgent
相关推荐
仓颉语言 std.sync 并发编程解析:AtomicBool 布尔原子操作实战指南
仓颉语言 std.sync 并发编程解析:AtomicBool 布尔原子操作实战指南 导读 std.sync 是仓颉语言标准库中面向并发编程的核心模块,而 At
人工智能AI 技能文档开发工具仓颉 std.sync 包详解:仓颉线程、原子操作与并发同步原语
仓颉 std.sync 包详解:仓颉线程、原子操作与并发同步原语 本文基于仓颉标准库 std.sync 包的官方概览文档( sync_package_overv
编程语言语言运行时标准库垃圾回收并发编程Glide Transformations快速上手:5分钟给Android图片加上模糊、圆角与头像效果
Glide Transformations快速上手:5分钟给Android图片加上模糊、圆角与头像效果 Glide Transformations 是一款为 A
人工智能AI 技能文档开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考