Skip to content

Commit 81d5fb5

Browse files
committed
新增std::atomic<std::shared_ptr> 的概念...... #12
1 parent 17c79ba commit 81d5fb5

File tree

1 file changed

+12
-0
lines changed

1 file changed

+12
-0
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ void f() {
4242

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

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

4749
在 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` 。例如:
@@ -415,6 +417,16 @@ else {
415417

416418
### `std::atomic<std::shared_ptr>`
417419

420+
在前文中,我们多次提到 `std::shared_ptr`
421+
422+
> 第四章中提到:*多个线程能在不同的 shared_ptr 对象上调用**所有成员函数**(包含复制构造函数与复制赋值)而不附加同步,即使这些实例是同一对象的副本且共享所有权也是如此。若多个执行线程访问同一 shared_ptr 对象而不同步,且任一线程使用 shared_ptr 的非 const 成员函数,则将出现数据竞争;`std::atomic<shared_ptr>` 能用于避免数据竞争。[文档](https://zh.cppreference.com/w/cpp/memory/shared_ptr#:~:text=%E5%A4%9A%E4%B8%AA%E7%BA%BF%E7%A8%8B%E8%83%BD%E5%9C%A8%E4%B8%8D%E5%90%8C%E7%9A%84%20shared_ptr%20%E5%AF%B9%E8%B1%A1%E4%B8%8A%E8%B0%83%E7%94%A8%E6%89%80%E6%9C%89%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0%EF%BC%88%E5%8C%85%E5%90%AB%E5%A4%8D%E5%88%B6%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E4%B8%8E%E5%A4%8D%E5%88%B6%E8%B5%8B%E5%80%BC%EF%BC%89%E8%80%8C%E4%B8%8D%E9%99%84%E5%8A%A0%E5%90%8C%E6%AD%A5%EF%BC%8C%E5%8D%B3%E4%BD%BF%E8%BF%99%E4%BA%9B%E5%AE%9E%E4%BE%8B%E6%98%AF%E5%90%8C%E4%B8%80%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%89%AF%E6%9C%AC%E4%B8%94%E5%85%B1%E4%BA%AB%E6%89%80%E6%9C%89%E6%9D%83%E4%B9%9F%E6%98%AF%E5%A6%82%E6%AD%A4%E3%80%82%E8%8B%A5%E5%A4%9A%E4%B8%AA%E6%89%A7%E8%A1%8C%E7%BA%BF%E7%A8%8B%E8%AE%BF%E9%97%AE%E5%90%8C%E4%B8%80%20shared_ptr%20%E5%AF%B9%E8%B1%A1%E8%80%8C%E4%B8%8D%E5%90%8C%E6%AD%A5%EF%BC%8C%E4%B8%94%E4%BB%BB%E4%B8%80%E7%BA%BF%E7%A8%8B%E4%BD%BF%E7%94%A8%20shared_ptr%20%E7%9A%84%E9%9D%9E%20const%20%E6%88%90%E5%91%98%E5%87%BD%E6%95%B0%EF%BC%8C%E5%88%99%E5%B0%86%E5%87%BA%E7%8E%B0%E6%95%B0%E6%8D%AE%E7%AB%9E%E4%BA%89%EF%BC%9Bstd%3A%3Aatomic%3Cshared_ptr%3E%20%E8%83%BD%E7%94%A8%E4%BA%8E%E9%81%BF%E5%85%8D%E6%95%B0%E6%8D%AE%E7%AB%9E%E4%BA%89%E3%80%82)。*
423+
424+
一个在互联网上非常热门的八股问题是:***`std::shared_ptr` 是不是线程安全?***
425+
426+
显然,它并不是完全线程安全的,尽管在多线程环境中有一定保证,但这还不够。在 C++20 中,原子模板 `std::atomic` 引入了一个偏特化版本 [`std::atomic<std::shared_ptr>`](https://zh.cppreference.com/w/cpp/memory/shared_ptr/atomic2) 允许用户原子地操纵 `shared_ptr` 对象。因为它是 `std::atomic` 的特化版本,即使我们还没有深入讲述它,也能知道它是**原子类型**,这意味着它的所有操作都是**原子操作**
427+
428+
若多个执行线程不同步地同时访问同一 `std::shared_ptr` 对象,且任何这些访问使用了 shared_ptr 的非 const 成员函数,则将**出现数据竞争****除非通过 `std::atomic<std::shared_ptr>` 的实例进行所有访问**
429+
418430
## 内存次序
419431

420432
### 前言

0 commit comments

Comments
 (0)