Skip to content

Commit 769cd53

Browse files
committed
1. 修改检查 std::atomic 类型是否满足要求的代码示例,使用静态断言
2. 修改 `std::atomic_flag` 一节的内容,添加对自旋锁实践的建议
1 parent 21f652d commit 769cd53

File tree

1 file changed

+17
-9
lines changed

1 file changed

+17
-9
lines changed

md/05内存模型与原子操作.md

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,17 @@ struct trivial_type {
162162
};
163163
```
164164

165-
验证自己的类型是否满足 `std::atomic` 要求,我们可以这样做
165+
验证自己的类型是否满足 `std::atomic` 要求,我们可以使用[静态断言](https://zh.cppreference.com/w/cpp/language/static_assert)
166166

167167
```cpp
168-
std::cout << std::boolalpha << std::is_trivially_copyable<trivial_type>::value << '\n';
169-
std::cout << std::boolalpha << std::is_copy_constructible<trivial_type>::value << '\n';
170-
std::cout << std::boolalpha << std::is_move_constructible<trivial_type>::value << '\n';
171-
std::cout << std::boolalpha << std::is_copy_assignable<trivial_type>::value << '\n';
172-
std::cout << std::boolalpha << std::is_move_assignable<trivial_type>::value << '\n';
168+
static_assert(std::is_trivially_copyable<trivial_type>::value, "");
169+
static_assert(std::is_copy_constructible<trivial_type>::value, "");
170+
static_assert(std::is_move_constructible<trivial_type>::value, "");
171+
static_assert(std::is_copy_assignable<trivial_type>::value, "");
172+
static_assert(std::is_move_assignable<trivial_type>::value, "");
173173
```
174174
175-
只要全部为 `true` 即可。显然我们的类型满足要求,我们可以尝试使用一下它:
175+
程序能通过编译即代表满足要求。如果不满足要求,静态断言求值中第一个表达式求值为 false,则编译错误。显然我们的类型满足要求,我们可以尝试使用一下它:
176176
177177
```cpp
178178
// 创建一个 std::atomic<trivial_type> 对象
@@ -191,7 +191,7 @@ std::cout << "交换前的 x: " << exchanged_value.x << ", 交换前的 y: " <<
191191
std::cout << "交换后的 x: " << atomic_my_type.load().x << ", 交换后的 y: " << atomic_my_type.load().y << std::endl;
192192
```
193193

194-
> [运行](https://godbolt.org/z/eTW64nGMz)测试。
194+
> [运行](https://godbolt.org/z/jG59c3b9M)测试。
195195
196196
没有问题,不过其实我们的 `trivial_type` 直接改成:
197197

@@ -202,7 +202,7 @@ struct trivial_type {
202202
};
203203
```
204204
205-
> [运行](https://godbolt.org/z/4oTf996xK)测试。
205+
> [运行](https://godbolt.org/z/ozPK1qefx)测试。
206206
207207
也是完全可以的,满足要求。先前只是为了展示一下显式写明的情况。
208208
@@ -295,6 +295,14 @@ void f(){
295295

296296
`flag` 对象的状态为设置 (`true`) 时,其线程调用 `test_and_set` 函数会返回 `true`,导致它们继续在循环中自旋,无法退出。直到先前持有锁的线程调用 `unlock()` 函数,将 `flag` 对象的状态原子地更改为清除 (`false`) 状态。此时,等待的线程中会有一个线程成功调用 `test_and_set` 返回 `false`,然后退出循环,成功获取锁。
297297

298+
> 值得注意的是,我们只是稍微的讲一下使用 `std::atomic_flag` 实现自旋锁。不过可没推荐各位在实践中使用它,具体可参见 **Linus Torvalds**[文章](https://www.realworldtech.com/forum/?threadid=189711&curpostid=189723)。其中有一段话说的很直接:
299+
>
300+
> - I repeat: **do not use spinlocks in user space, unless you actually know what you're doing**. And be aware that the likelihood that you know what you are doing is basically nil.
301+
>
302+
> > 我再说一遍:不要在用户空间中使用自旋锁,除非你真的知道自己在做什么。请注意,你知道自己在做什么的可能性基本上为零。
303+
>
304+
>然后就是推荐 `std::mutex``pthread_mutex` ,比自旋好的多。
305+
298306
`std::atomic_flag` 的局限性太强,甚至不能当普通的 bool 标志那样使用。一般最好使用 `std::atomic<bool>`,下节,我们来使用它。
299307

300308
## 内存次序

0 commit comments

Comments
 (0)