C++ 中原子标志和原子布尔值的区别

2025年3月22日 | 阅读4分钟

在本文中,我们将讨论 C++ 中原子标志原子布尔值之间的区别。在讨论它们的区别之前,我们必须了解 C++ 中的原子标志和原子布尔值。

什么是原子标志 (std::atomic_flag)?

C++ 低级原子类型 std::atomic_flag 可以处于两种状态之一:设置 (true) 或清除 (false)。它提供两个主要操作:test_and_set() 设置标志并返回调用时的值,clear() 将标志重置为 false。它最初为 false。std::atomic_flag 函数主要用于同步原语(例如,自旋锁),不能复制或赋值。当最少的原子操作可以实现线程同步时,它最适用于低级、性能关键的应用程序。

目的

std::atomic_flag 函数是一种低级原子类型,可以用作简单的锁或标志机制。在所有情况下,它要么清除,要么设置。

状态变化

  • 初始清除:它始终以清除 (false) 状态开始。
  • 测试和设置:由于主要方法 test_and_set(),它们基本上可以通过它实现。它在返回先前值为 true 之前设置标志。
  • 清除:可以通过使用 clear() 物理移除标志。
  • 用例:它通常用于低级同步技术,如自旋锁,或在互斥锁等更高级别的抽象成本过高时实现互斥(临界区)。
  • 不可复制或赋值:Std::atomic_flag 仅支持 test_and_set 和 clear 操作;不允许复制或赋值。

什么是原子布尔值 (std::atomic<bool>)?

std::atomic bool 值可以在线程之间交换而不会发生数据竞争。它提供了 std::atomic_flag 提供的原子操作的超集:load()、store()、exchange() 和 compare_exchange()。此外,它允许我们直接初始化和修改布尔值。它使用户能够直接初始化和修改布尔值。它提高了其在多线程系统中常见用例(如信号情况或线程生命周期管理)中的多功能性和适应性。因为它支持多种内存顺序,所以它适用于更复杂的同步问题。

  • 目的
    完整的原子类型 std::atomic 包含一个布尔值。与 atomic_flag 相比,它提供了更多的操作。

状态修改

  • 布尔值可以连接到 true 或 false。
  • load()、store()、compare_exchange() 和 exchange() 等常见的原子函数可用于原子地获取或设置其值。
  • 应用以下场景:在以线程安全的方式处理线程之间的共享布尔值时,它很有用。例如,控制线程的生命周期或实现线程间通信。
  • 增强的灵活性:与 atomic_flag 不同,您可以使用 std::atomic 直接赋值和读取值,它还支持所有典型的原子操作。

C++ 中 std::atomic_flag 和 std::atomic<bool> 之间的主要区别

C++ 中 std::atomic_flag 和 std::atomic<bool> 之间存在几个主要区别。一些主要区别如下

特点Std::atomic_flagStd::atomic<bool>
状态设置 (true) 或清除 (false)True 或 False
操作Test_and_set()、clear()load()、store()、exchange()、compare_exchange()
初始化它始终初始化为 false (清除)。在这些函数中,用户可以初始化为 true 或 false。
赋值它不可复制或赋值。它可复制和赋值。
用例它是低级同步。
例如:自旋锁
它是通用原子布尔值管理。
内存排序在内存排序中,它仅支持获取-释放顺序。它支持所有内存顺序(例如:relaxed、acquire、release、seq_cst)
性能开销它针对有限功能(仅 test_and_set() 和 clear())进行了优化,这意味着它提供的操作更少,通常开销更小,因此对于低级同步工作更快。当使用更复杂的程序(如 compare_exchange())时,std::atomic<bool> 比 std::atomic_flag 会产生略高的性能成本。但是,它提供了最多的操作和灵活性。
在自旋锁中的使用它常用的自旋锁方法非常适合忙等待,因为它允许线程重复使用 test_and_set(),直到它设法获取到标志。std::atomic<bool> 有一个有用的类似 test_and_set() 的方法,专门为这些任务设计,自旋锁通常不使用它,但同步可能会使用。

结论

总之,std::atomic_flagstd::atomic<bool> 都用于使我们的 C++ 代码在多线程中更安全,但两者在复杂性和适用性方面存在显著差异。较轻的 std::atomic_flag 类型更适合低级同步任务,例如自旋锁,当基本操作仅包括设置和清除标志时。然而,在高级同步中,当需要操作共享布尔值时,std::atomic 会更受欢迎,因为它更灵活;它支持更广泛的操作和内存顺序。哪种方法最好取决于特定用例的同步具体要求。