File tree 2 files changed +44
-1
lines changed
2 files changed +44
-1
lines changed Original file line number Diff line number Diff line change @@ -1044,6 +1044,6 @@ CPU 变量的概念很好理解。就像线程变量为每个线程提供独立
1044
1044
1045
1045
## 总结
1046
1046
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 变量,和各种变量进行了一个对比 。
1048
1048
1049
1049
下一章,我们将开始讲述同步操作,会使用到 [**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)等设施。
Original file line number Diff line number Diff line change @@ -417,6 +417,49 @@ else {
417
417
418
418
### ` std::atomic<T*> `
419
419
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
+
420
463
### `std::atomic<std::shared_ptr>`
421
464
422
465
在前文中,我们多次提到 `std::shared_ptr`:
You can’t perform that action at this time.
0 commit comments