Skip to content

Commit 882aa86

Browse files
committed
1. 初步完成 std::atomic<bool>(不是很满意)
2. 为前面 `std::atomic` 增加一个提示总结 3. 修改第二章,新建一节 `std::jthread`(只有标题)
1 parent f9d3eb5 commit 882aa86

File tree

2 files changed

+66
-1
lines changed

2 files changed

+66
-1
lines changed

md/02使用线程.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,8 @@ int main(){
866866
867867
如果你自己编译了这些代码,相信你注意到了,打印的是乱序的,没什么规律,而且重复运行的结果还不一样,**这是正常现象**。多线程执行就是如此,无序且操作可能被打断。使用互斥量可以解决这些问题,这也就是下一章节的内容了。
868868
869+
## C++20 `std::jthread`
870+
869871
## 总结
870872
871873
本章节的内容围绕着:“使用线程”,也就是"**使用 `std::thread`**"展开, `std::thread` 是我们学习 C++ 并发支持库的重中之重,本章的内容在市面上并不少见,但是却是少有的准确与完善。即使你早已学习乃至使用 C++ 标准库进行多线程编程,我相信本章也一定可以让你收获良多。

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

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ struct trivial_type {
216216
217217
3. **Read-modify-write(读-改-写)操作**:可选的内存序包括 `memory_order_relaxed`、`memory_order_consume`、`memory_order_acquire`、`memory_order_release`、`memory_order_acq_rel`、`memory_order_seq_cst`。
218218
219+
> 本节主要广泛介绍 `std::atomic`,而未展开具体使用。在后续章节中,我们将更详细地讨论一些版本,如 `std::atomic<bool>`,并介绍其成员函数和使用方法。
220+
219221
### `st::atomic_flag`
220222
221223
`std::atomic_flag` 是最简单的原子类型,这个类型的对象可以在两个状态间切换:**设置(true)**和**清除(false)**。它很简单,通常只是用作构建一些库设施,不会单独使用或直接面向普通开发者。
@@ -336,7 +338,7 @@ bool new_value = (b = false); // new_value 将是 false
336338
337339
获取 `std::atomic<bool>` 的值有两种方式,调用 `load()` 函数,或者[隐式转换](https://zh.cppreference.com/w/cpp/atomic/atomic/operator_T)。
338340
339-
`store` 是一个存储操作、`load` 是一个加载操作、`exchange` 是一个“读-改-写”操作:
341+
`store` 是一个存储操作、`load` 是一个*加载操作*、`exchange` 是一个“*读-改-写*”操作:
340342
341343
```cpp
342344
std::atomic<bool> b;
@@ -345,6 +347,67 @@ b.store(true);
345347
x = b.exchange(false, std::memory_order_acq_rel);
346348
```
347349

350+
---
351+
352+
`std::atomic<bool>` 提供多个“*读-改-写*”的操作,exchange 只是其中之一。它还提供了一种存储方式:**当前值与预期一致时,存储新值。**
353+
354+
这种操作叫做“比较/交换”,它的形式表现为 [`compare_exchange_weak()`](https://zh.cppreference.com/w/cpp/atomic/atomic/compare_exchange)`compare_exchang_strong()`
355+
356+
- **compare_exchange_weak**:尝试将原子对象的当前值与预期值进行*比较*[^1],如果相等则将其更新为新值并返回 `true`;否则,将原子对象的值加载进 expected(进行加载操作)并返回 `false`**此操作可能会由于某些硬件的特性而出现*假失败*[^2],需要在循环中重试**
357+
358+
```cpp
359+
std::atomic<bool> flag{ false };
360+
bool expected = false;
361+
362+
while (!flag.compare_exchange_weak(expected, true));
363+
```
364+
365+
> [运行](https://godbolt.org/z/YToPYf3hd)测试。
366+
367+
返回 `false` 即代表出现了*假失败*,因此需要在循环中重试。。
368+
369+
- **compare_exchange_strong**:类似于 `compare_exchange_weak`,**但不会出现假失败,因此不需要重试**。适用于需要确保操作成功的场合。
370+
371+
```cpp
372+
std::atomic<bool> flag{ false };
373+
bool expected = false;
374+
375+
void try_set_flag() {
376+
// 尝试将 flag 设置为 true,如果当前值为 false
377+
if (flag.compare_exchange_strong(expected, true)) {
378+
std::cout << "flag 为 false,设为 true。\n";
379+
}
380+
else {
381+
std::cout << "flag 为 true, expected 设为 true。\n";
382+
}
383+
}
384+
```
385+
386+
> [运行](https://godbolt.org/z/zz4q8vsoe)测试。
387+
388+
假设有两个线程运行 `try_set_flag` 函数,那么第一个线程调用 `compare_exchange_strong` 将原子对象 `flag` 设置为 `true`。第二个线程调用 `compare_exchange_strong`,当前原子对象的值为 `true`,而 `expected``false`,不相等,将原子对象的值设置给 `expected`。此时 `flag``expected` 均为 `true`
389+
390+
`exchang` 的另一个不同是,`compare_exchange_weak``compare_exchange_strong` 允许指定成功和失败情况下的内存序。这意味着你可以根据成功或失败的情况,为原子操作指定不同的内存序。
391+
392+
```cpp
393+
std::atomic<bool> data{ false };
394+
bool expected = false;
395+
396+
// 成功时的内存序为 memory_order_release,失败时的内存序为 memory_order_acquire
397+
if (data.compare_exchange_weak(expected, true, std::memory_order_release, std::memory_order_acquire)) {
398+
// 操作成功
399+
}
400+
else {
401+
// 操作失败
402+
}
403+
```
404+
405+
另一个简单的原子类型是特化的原子指针,即:**`std::atomic<T*>`**,下一节我们来看看它是如何工作的。
406+
407+
[^1]:注: 比较和复制是逐位的(类似 [std::memcmp](https://zh.cppreference.com/w/cpp/string/byte/memcmp)[std::memcpy](https://zh.cppreference.com/w/cpp/string/byte/memcpy));不使用构造函数、赋值运算符或比较运算符。
408+
409+
[^2]:注:即使 expected 与原子对象的值相等,表现如同 `*this != expected`
410+
348411
### `std::atomic<T*>`
349412

350413
### `std::atomic<std::shared_ptr>`

0 commit comments

Comments
 (0)