File tree Expand file tree Collapse file tree 1 file changed +12
-0
lines changed Expand file tree Collapse file tree 1 file changed +12
-0
lines changed Original file line number Diff line number Diff line change @@ -42,6 +42,8 @@ void f() {
42
42
43
43
标准原子类型定义在头文件 [ ` <atomic> ` ] ( https://zh.cppreference.com/w/cpp/header/atomic ) 中。这些类型的操作都是原子的,语言定义中只有这些类型的操作是原子的,虽然也可以用互斥量来模拟原子操作(见上文)。标准的原子的类型实现可能是:* 它们几乎都有一个 ` is_lock_free() ` 成员函数,这个函数可以让用户查询某原子类型的操作是直接用的原子指令(返回 ` true ` ),还是内部用了锁实现(返回 ` false ` )。*
44
44
45
+ > 每个 ` std::atomic ` 模板的实例化和全特化均定义一个原子类型。** 如果一个线程写入原子对象,同时另一线程从它读取,那么行为有良好定义** (数据竞争的细节见[ 内存模型] ( https://zh.cppreference.com/w/cpp/language/memory_model ) )。
46
+
45
47
原子操作可以代替互斥量,来进行同步操作,也能带来更高的性能。但是如果它的内部使用互斥量实现,那么不可能有性能的提升。
46
48
47
49
在 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 {
415
417
416
418
### ` std::atomic<std::shared_ptr> `
417
419
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
+
418
430
## 内存次序
419
431
420
432
### 前言
You can’t perform that action at this time.
0 commit comments