C++:std::memory_order_relaxed(宽松内存序)
std::memory_order_relaxed 的含义
std::memory_order_relaxed 是 C++11 标准提供的几种内存序之一,表示该操作不需要与其他内存操作的顺序有任何关系。换句话说,使用 memory_order_relaxed 进行的读写操作只保证了这个操作本身的原子性,但不提供同步或顺序一致性的保证。
具体来说,使用 memory_order_relaxed 具有以下特点:
- 原子性: 即使使用 memory_order_relaxed,操作本身仍然是原子的,保证在并发情况下,多个线程不会看到部分更新的值。
- 无顺序保证: 与其他线程的操作顺序没有关系。编译器和处理器可以随意重排这些操作,但重排后的行为在每个线程内仍然是一致的。
- 性能优化: 由于没有顺序或同步的要求,memory_order_relaxed 可以在一些情况下减少同步开销,提高性能。尤其在不关心其他线程的执行顺序时,这种模式非常适用。
使用场景
memory_order_relaxed 通常用于以下场景:
- 无数据依赖的计数器: 如果你有一个全局计数器,多个线程只需要对它进行递增操作,而不关心其他线程的操作顺序,这时可以使用 memory_order_relaxed 来减少同步开销。
std::atomic<int> counter(0);void increment() {counter.fetch_add(1, std::memory_order_relaxed);
}
- 非同步标志变量: 在某些情况下,你可能有一个标志变量,多个线程需要读取这个变量,但它们不依赖于其他线程的读写顺序。
std::atomic<bool> flag(false);void set_flag() {flag.store(true, std::memory_order_relaxed);
}bool check_flag() {return flag.load(std::memory_order_relaxed);
}
- 单例模式中的懒初始化: 在双重检查锁定模式中,如果我们只关心是否已经初始化过,而不关心线程之间的顺序性,可以使用 memory_order_relaxed 来提升性能。
std::atomic<Singleton*> _instance(nullptr);
std::mutex _mutex;Singleton* Singleton::getInstance() {Singleton* tmp = _instance.load(std::memory_order_relaxed);if (tmp == nullptr) {std::lock_guard<std::mutex> lock(_mutex);tmp = _instance.load(std::memory_order_relaxed);if (tmp == nullptr) {tmp = new Singleton();_instance.store(tmp, std::memory_order_release);}}return tmp;
}
在这个例子中:
- memory_order_relaxed 用于读取 _instance,因为我们在第一次检查时不关心其他线程的执行顺序。
- 如果对象还没有初始化,进入锁定区域时再次使用 memory_order_relaxed 进行检查。
- 一旦对象被创建,使用 memory_order_release 进行存储,确保其他线程在读取时能够看到最新的值。
总结
memory_order_relaxed 是一种在不关心线程间操作顺序的情况下使用的内存序。它只保证操作的原子性,而不保证操作的顺序一致性,因此可以提高性能,适用于那些对顺序不敏感的场景,如计数器、标志变量以及单例模式中的双重检查锁定等。在这些场景中,正确使用 memory_order_relaxed 可以避免不必要的同步开销,提升并发程序的执行效率。