在 C++ 中,std::atomic
是一个模板类,用于实现原子操作。原子操作是不可分割的操作,即在多线程环境中,一个线程执行原子操作时,不会被其他线程中断。std::atomic
提供了一种高效的方式来保证多线程环境下的数据同步,避免了使用锁(如 std::mutex
)带来的性能开销。
1. std::atomic
的核心概念
- 原子性:
- 原子操作是不可分割的,要么完全执行,要么完全不执行。
- 在多线程环境中,原子操作可以避免数据竞争(Data Race)。
- 内存顺序:
std::atomic
支持多种内存顺序(Memory Order),用于控制原子操作的可见性和顺序性。- 内存顺序决定了其他线程看到原子操作的顺序。
- 无锁编程:
std::atomic
是实现无锁数据结构(Lock-Free Data Structures)的基础。- 无锁编程可以提高并发性能,但实现复杂度较高。
2. std::atomic
的常用操作
std::atomic
提供了多种原子操作,常用的操作包括:
(1)加载(Load)
- 从原子变量中读取值。
(2)存储(Store)
- 向原子变量中写入值。
(3)读-修改-写操作
fetch_add
:原子地增加变量的值,并返回旧值。fetch_sub
:原子地减少变量的值,并返回旧值。exchange
:原子地交换变量的值,并返回旧值。compare_exchange_weak
和compare_exchange_strong
:- 比较并交换操作,用于实现无锁数据结构。
3. 内存顺序(Memory Order)
std::atomic
支持多种内存顺序,用于控制原子操作的可见性和顺序性。常用的内存顺序包括:
内存顺序 | 特性 |
---|---|
memory_order_relaxed | 只保证原子性,不保证顺序性和可见性。 |
memory_order_consume | 保证数据依赖的顺序性(较少使用)。 |
memory_order_acquire | 保证后续操作不会重排序到加载操作之前,确保看到释放操作之前的写入。 |
memory_order_release | 保证之前操作不会重排序到存储操作之后,确保写入对获取操作可见。 |
memory_order_acq_rel | 结合获取和释放语义,适用于读-修改-写操作。 |
memory_order_seq_cst | 保证全局一致性,所有线程看到的操作顺序一致(默认内存顺序)。 |
4. std::atomic
的使用场景
(1)计数器
- 使用
fetch_add
或fetch_sub
实现线程安全的计数器。
(2)标志位
- 使用
std::atomic<bool>
实现线程安全的标志位。
(3)无锁数据结构
- 使用
compare_exchange_weak
或compare_exchange_strong
实现无锁队列、栈等数据结构。
5. std::atomic
的示例
以下是一个完整的示例,展示了 std::atomic
的使用:
#include <iostream>
#include <atomic>
#include <thread>
std::atomic<int> counter{0};
void increment() {
for (int i = 0; i < 100000; ++i) {
counter.fetch_add(1, std::memory_order_relaxed);
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << "Counter: " << counter.load() << std::endl;
return 0;
}
6. 总结
std::atomic
是 C++ 中用于实现原子操作的模板类,提供了高效的线程同步机制。- 它支持多种原子操作(如加载、存储、读-修改-写操作)和内存顺序。
std::atomic
适用于计数器、标志位、无锁数据结构等场景。- 通过合理使用
std::atomic
,可以在多线程环境中避免数据竞争,同时减少锁的开销。
THE END
暂无评论内容