Skip to content

Commit

Permalink
更新第五章 std::atomic 措辞以及补充描述
Browse files Browse the repository at this point in the history
  • Loading branch information
Mq-b committed Sep 27, 2024
1 parent 8f46c3f commit f9eed73
Showing 1 changed file with 8 additions and 4 deletions.
12 changes: 8 additions & 4 deletions md/05内存模型与原子操作.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ void f() {

### 原子类型 `std::atomic`

标准原子类型定义在头文件 [`<atomic>`](https://zh.cppreference.com/w/cpp/header/atomic) 中。这些类型的操作都是原子的,语言定义中只有这些类型的操作是原子的,虽然也可以用互斥量来模拟原子操作(见上文)。标准的原子的类型实现可能是:*它们几乎都有一个 `is_lock_free()` 成员函数,这个函数可以让用户查询某原子类型的操作是直接用的原子指令(返回 `true`),还是内部用了锁实现(返回 `false`)。*
标准原子类型定义在头文件 [`<atomic>`](https://zh.cppreference.com/w/cpp/header/atomic) 中。这些类型的操作都是原子的,语言定义中只有这些类型的操作是原子的,虽然也可以用互斥量来模拟原子操作(见上文)。

> 每个 `std::atomic` 模板的实例化和全特化均定义一个原子类型。**如果一个线程写入原子对象,同时另一线程从它读取,那么行为有良好定义**(数据竞争的细节见[内存模型](https://zh.cppreference.com/w/cpp/language/memory_model))。
标准原子类型的实现通常包括一个 `is_lock_free()` 成员函数,允许用户查询特定原子类型的操作是否是通过直接的原子指令实现(返回 true),还是通过锁来实现(返回 false)。

原子操作可以代替互斥量,来进行同步操作,也能带来更高的性能。但是如果它的内部使用互斥量实现,那么不可能有性能的提升。
> **如果一个线程写入原子对象,同时另一线程从它读取,那么行为有良好定义**(数据竞争的细节见[内存模型](https://zh.cppreference.com/w/cpp/language/memory_model))。
原子操作可以在一些时候代替互斥量,来进行同步操作,也能带来更高的性能。但是如果它的内部使用互斥量实现,那么不可能有性能的提升。

在 C++17 中,所有原子类型都有一个 `static constexpr` 的数据成员 [`is_always_lock_free`](https://zh.cppreference.com/w/cpp/atomic/atomic/is_always_lock_free) 。如果当前环境上的原子类型 X 是无锁类型,那么 `X::is_always_lock_free` 将返回 `true` 。例如:

Expand Down Expand Up @@ -101,7 +103,7 @@ else {

因为 `is_always_lock_free` 是编译期常量,所以我们可以使用 C++17 引入的 `constexpr if` ,它可以在编译阶段进行决策,避免了运行时的判断开销,提高了性能。

宏则更是简单了,最基本的预处理器判断,在预处理阶段就选择执行合适的代码
宏则更是简单了,最基本的预处理器判断,在预处理阶段就选择编译合适的代码

在实际应用中,如果一个类型的原子操作总是无锁的,我们可以更放心地在性能关键的代码路径中使用它。例如,在高频交易系统、实时系统或者其它需要高并发性能的场景中,无锁的原子操作可以显著减少锁的开销和争用,提高系统的吞吐量和响应时间。

Expand All @@ -111,6 +113,8 @@ else {
2. **减少原子操作的频率**:通过批处理等技术,减少对原子操作的调用次数。
3. **使用更高效的同步机制**:在一些情况下,其它同步机制(如读写锁)可能比原子操作更高效。

当然,其实很多时候根本没这种性能的担忧,我们很多时候使用原子对象只是为了简单方便,比如 `std::atomic<bool>` 表示状态、`std::atomic<int>` 进行计数等。即使它们是用了锁,那也是封装好了的,起码用着方便,而不需要在代码中引入额外的互斥量来保护,更加简洁。这也是很正常的需求,各位不但要考虑程序的性能,同时也要考虑代码的简洁性、易用性。即使使用原子类型无法带来效率的提升,那也没有负提升。

---

除了直接使用 `std::atomic` 模板外,也可以使用原子类型的别名。这个数量非常之多,见 [MSVC STL](https://github.com/microsoft/STL/blob/daeb0a6/stl/inc/atomic#L2745-L2805)。
Expand Down

0 comments on commit f9eed73

Please sign in to comment.