Skip to content

Commit e74c3e1

Browse files
committed
1. 修改第三章总结的内容
2. 完成第五章,`std::atomic<T*>` 的特化
1 parent 567822f commit e74c3e1

File tree

2 files changed

+44
-1
lines changed

2 files changed

+44
-1
lines changed

md/03共享数据.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,6 @@ CPU 变量的概念很好理解。就像线程变量为每个线程提供独立
10441044
10451045
## 总结
10461046
1047-
本章讨论了多线程的共享数据引发的恶性条件竞争会带来的问题。并说明了可以使用互斥量(`std::mutex`)保护共享数据,并且要注意互斥量上锁的“**粒度**”。C++标准库提供了很多工具,包括管理互斥量的管理类(`std::lock_guard`),但是互斥量只能解决它能解决的问题,并且它有自己的问题(**死锁**)。同时我们讲述了一些避免死锁的方法和技术。还讲了一下互斥量所有权转移。然后讨论了面对不同情况保护共享数据的不同方式,使用 `std::call_once()` 保护共享数据的初始化过程,使用读写锁(`std::shared_mutex`)保护不常更新的数据结构。以及特殊情况可能用到的互斥量 `recursive_mutex`,有些人可能喜欢称作:**递归锁**。最后聊了一下 `new`、`delete` 运算符的库函数实际是线程安全的,以及线程存储期
1047+
本章讨论了多线程的共享数据引发的恶性条件竞争会带来的问题。并说明了可以使用互斥量(`std::mutex`)保护共享数据,并且要注意互斥量上锁的“**粒度**”。C++标准库提供了很多工具,包括管理互斥量的管理类(`std::lock_guard`),但是互斥量只能解决它能解决的问题,并且它有自己的问题(**死锁**)。同时我们讲述了一些避免死锁的方法和技术。还讲了一下互斥量所有权转移。然后讨论了面对不同情况保护共享数据的不同方式,使用 `std::call_once()` 保护共享数据的初始化过程,使用读写锁(`std::shared_mutex`)保护不常更新的数据结构。以及特殊情况可能用到的互斥量 `recursive_mutex`,有些人可能喜欢称作:**递归锁**。然后聊了一下 `new`、`delete` 运算符的库函数实际是线程安全的。最后介绍了一下线程存储期、CPU 变量,和各种变量进行了一个对比
10481048
10491049
下一章,我们将开始讲述同步操作,会使用到 [**Futures**](https://zh.cppreference.com/w/cpp/thread#.E6.9C.AA.E6.9D.A5.E4.BD.93)、[**条件变量**](https://zh.cppreference.com/w/cpp/thread#.E6.9D.A1.E4.BB.B6.E5.8F.98.E9.87.8F)等设施。

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,49 @@ else {
417417

418418
### `std::atomic<T*>`
419419

420+
`std::atomic<T*>` 是一个原子指针类型,`T` 是指针所指向的对象类型。操作是针对 `T` 类型的指针进行的。虽然 `std::atomic<T*>` 不能被拷贝和移动,但它可以通过符合类型的指针进行构造和赋值。
421+
422+
`std::atomic<T*>` 拥有以下成员函数:
423+
424+
- `load()`:以原子方式读取指针值。
425+
- `store()`:以原子方式存储指针值。
426+
- `exchange()`:以原子方式交换指针值。
427+
- `compare_exchange_weak()``compare_exchange_strong()`:以原子方式比较并交换指针值。
428+
429+
这些函数接受并返回的类型都是 **T***。此外,`std::atomic<T*>` 还提供了以下操作:
430+
431+
- `fetch_add`:以原子方式增加指针的值。(`p.fetch_add(1)` 会将指针 `p` 向前移动一个元素,并返回操作前的指针值)
432+
433+
- `fetch_sub`:以原子方式减少指针的值。返回操作前的指针值。
434+
435+
- `operator+=``operator-=`:以原子方式增加或减少指针的值。返回操作前的指针值。
436+
437+
这些操作确保在多线程环境下进行安全的指针操作,避免数据竞争和并发问题。
438+
439+
使用示例如下:
440+
441+
```cpp
442+
struct Foo {};
443+
444+
Foo array[5]{};
445+
std::atomic<Foo*> p{ array };
446+
447+
// p 加 2,并返回原始值
448+
Foo* x = p.fetch_add(2);
449+
assert(x == array);
450+
assert(p.load() == &array[2]);
451+
452+
// p 减 1,并返回原始值
453+
x = (p -= 1);
454+
assert(x == &array[1]);
455+
assert(p.load() == &array[1]);
456+
457+
// 函数也允许内存序作为给定函数的参数
458+
p.fetch_add(3, std::memory_order_release);
459+
```
460+
461+
这个特化十分简单,我们无需过多赘述。
462+
420463
### `std::atomic<std::shared_ptr>`
421464
422465
在前文中,我们多次提到 `std::shared_ptr`:

0 commit comments

Comments
 (0)