std::memory_order 多线程编程中的内存顺序
std::memory_order
是 C++11 引入的一个枚举,用于控制多线程编程中的内存顺序。它定义了在原子操作中对内存的可见性和排序的要求。它在 C++ 标准库的 <atomic>
头文件中,配合原子类型和操作(如 std::atomic
和 std::atomic_flag
)使用,以确保不同线程之间的数据同步。
下面是 std::memory_order
的每个成员及其作用:
1. std::memory_order_relaxed
- 作用:执行无序原子操作,不提供顺序一致性保证。不同线程之间的操作可以乱序,适用于对性能要求高且数据同步要求低的场景。
- 特点:只保证当前原子变量的操作是原子的,但不保证该操作与其他内存操作的相对顺序。
- 适用场景:计数器、统计等无需严格同步的数据结构。
2. std::memory_order_consume
- 作用:确保当前线程中对原子变量的操作和之后的读操作有顺序关系,但不保证写操作的顺序。
- 特点:在某些特定平台上能比
memory_order_acquire
更高效(例如 ARM),但支持较差,通常会被编译器提升为memory_order_acquire
。 - 适用场景:不常用,通常用
memory_order_acquire
替代。
3. std::memory_order_acquire
- 作用:获取同步,确保在该线程中,所有在此原子操作之前的内存写入对后续的读操作可见。
- 特点:防止在获取操作后发生的读写操作被重排序到获取操作之前。
- 适用场景:适合读操作,例如在读取一个共享变量时,需要确保读取的内容是最新的。
4. std::memory_order_release
- 作用:释放同步,确保在该线程中,所有在此原子操作之前的内存写入对其他线程可见。
- 特点:防止在释放操作之前的写入操作被重排序到释放操作之后。
- 适用场景:适合写操作,通常在向其他线程发布信息或更新状态时使用。
5. std::memory_order_acq_rel
- 作用:同时包含获取和释放语义,用于读写操作,确保此线程之前的所有写操作可见,之后的所有读操作会看到更新。
- 特点:读写操作均同步,防止操作的重排序。
- 适用场景:适合同时包含读取和写入的操作,常用于读-修改-写的操作中。
6. std::memory_order_seq_cst
(Sequentially Consistent)
- 作用:顺序一致性,最强的内存顺序保证,确保所有的原子操作在全局顺序上是唯一的。
- 特点:确保线程间的操作严格按顺序发生,所有线程都看到一致的内存修改顺序。
- 适用场景:适合对内存顺序要求严格的场景,但性能可能较低。标准库中的原子操作默认使用此顺序。
总结
Memory Order | 作用 | 适用场景 |
---|---|---|
memory_order_relaxed | 不保证内存顺序,仅确保原子性 | 无需同步的简单计数操作 |
memory_order_consume | 仅确保后续读操作的顺序关系 | 很少使用,通常用 acquire 替代 |
memory_order_acquire | 确保获取操作前的写操作不会重排,适合读操作 | 读取共享数据,确保读取的是最新数据 |
memory_order_release | 确保释放操作后的写操作不会重排,适合写操作 | 发布信息或更新状态 |
memory_order_acq_rel | 读写均同步,防止重排 | 读-修改-写的操作 |
memory_order_seq_cst | 全局唯一顺序,最严格的内存保证 | 对顺序要求严格的操作 |
示例
以下是一个简单例子,展示如何使用 memory_order_release
和 memory_order_acquire
来实现同步:
#include <atomic>
#include <thread>
#include <iostream>
std::atomic<bool> ready(false);
std::atomic<int> data(0);
void producer() {
data.store(42, std::memory_order_relaxed); // 写入数据
ready.store(true, std::memory_order_release); // 发布信息
}
void consumer() {
while (!ready.load(std::memory_order_acquire)) { // 等待信息发布
// busy-wait
}
std::cout << "Data: " << data.load(std::memory_order_relaxed) << std::endl; // 读取数据
}
int main() {
std::thread t1(producer);
std::thread t2(consumer);
t1.join();
t2.join();
return 0;
}
在此代码中:
producer
线程先写入数据,然后发布ready
状态,使用memory_order_release
确保data
的写入在ready
状态更新之前完成。consumer
线程使用memory_order_acquire
加载ready
,以确保读取到true
状态时,data
中的值已经更新。