diff --git a/.gitignore b/.gitignore
index ab308736..ac6a9ca8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,6 +41,9 @@ node_modules/
.vs/
x64/
out/
+bin/
+*.ilk
+*.pdb
CMakePresets.json
CMakeUserPresets.json
diff --git a/.vuepress/config.js b/.vuepress/config.js
index 4efb8f0e..889cb274 100644
--- a/.vuepress/config.js
+++ b/.vuepress/config.js
@@ -28,6 +28,7 @@ export default defineUserConfig({
{ text: 'std::thread 的构造-源码解析', link: srcCodePath + '01thread的构造与源码解析', },
{ text: 'std::scoped_lock 的源码实现与解析', link: srcCodePath + '02scoped_lock源码解析', },
{ text: 'std::async 与 std::future 源码解析', link: srcCodePath + '03async与future源码解析', },
+ { text: '线程池', link: srcCodePath + "04线程池", },
]
},
],
@@ -41,8 +42,32 @@ export default defineUserConfig({
pageInfo: ['ReadingTime'],
plugins: {
mdEnhance: {
+ gfm: true,
+ hint: true,
+ vPre: true,
+ alert: true,
+ tabs: true,
+ codetabs: true,
+ align: true,
+ attrs: true,
+ sup: true,
+ sub: true,
footnote: true,
- imgLazyload: true
+ mark: true,
+ figure: true,
+ imgLazyload: true,
+ imgMark: true,
+ imgSize: true,
+ obsidianImgSize: true,
+ tasklist: true,
+ include: true,
+ katex: true,
+ component: true,
+ chart: true,
+ echarts: true,
+ flowchart: true,
+ mermaid: true,
+ plantuml: true,
},
searchPro: true
}
diff --git a/.vuepress/params.js b/.vuepress/params.js
index eee102f7..cfb73ec8 100644
--- a/.vuepress/params.js
+++ b/.vuepress/params.js
@@ -3,5 +3,7 @@ const logoPath = '/image/现代C++并发编程教程.png';
const repoName = '现代C++并发编程教程';
const repoBase = '/ModernCpp-ConcurrentProgramming-Tutorial';
const repoUrl = `https://github.com/Mq-b${repoBase}/`;
+const sponsor = '/image/赞助.jpg';
+const cat = '/image/猫猫虫旋转.jpg'
-export { repoUrl, repoBase, repoName, logoPath }
\ No newline at end of file
+export { repoUrl, repoBase, repoName, logoPath, sponsor, cat }
\ No newline at end of file
diff --git "a/.vuepress/public/image/\347\214\253\347\214\253\350\231\253\346\227\213\350\275\254.jpg" "b/.vuepress/public/image/\347\214\253\347\214\253\350\231\253\346\227\213\350\275\254.jpg"
new file mode 100644
index 00000000..f2c960c5
Binary files /dev/null and "b/.vuepress/public/image/\347\214\253\347\214\253\350\231\253\346\227\213\350\275\254.jpg" differ
diff --git "a/.vuepress/public/image/\350\265\236\345\212\251.jpg" "b/.vuepress/public/image/\350\265\236\345\212\251.jpg"
new file mode 100644
index 00000000..22adddd4
Binary files /dev/null and "b/.vuepress/public/image/\350\265\236\345\212\251.jpg" differ
diff --git a/README.md b/README.md
index 4e4f62b5..415527f9 100644
--- a/README.md
+++ b/README.md
@@ -6,11 +6,11 @@
# 现代C++并发编程教程
-本仓库用来存放 B 站课程[《现代 C++ 并发编程教程》]()的教案、代码。
+本仓库用来存放 B 站课程[《现代 C++ 并发编程教程》](https://www.bilibili.com/cheese/play/ss34184)的教案、代码。
不管是否购买课程,任何组织和个人遵守 [CC BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/deed.zh-hans) 协议均可随意使用学习。
-[捐赠](/image/捐赠)、[issues](https://github.com/Mq-b/ModernCpp-ConcurrentProgramming-Tutorial/issues)、[pr](https://github.com/Mq-b/ModernCpp-ConcurrentProgramming-Tutorial/pulls) 均会在致谢列表中**铭记您的贡献**。
+[捐赠](https://github.com/Mq-b/ModernCpp-ConcurrentProgramming-Tutorial/tree/main/image/%E6%8D%90%E8%B5%A0)、[issues](https://github.com/Mq-b/ModernCpp-ConcurrentProgramming-Tutorial/issues)、[pr](https://github.com/Mq-b/ModernCpp-ConcurrentProgramming-Tutorial/pulls) 均会在致谢列表中**铭记您的贡献**。
@@ -25,3 +25,16 @@
虽强调现代,但不用担心,我们几乎是从头教学,即使你从来没使用过 C++ 进行多线程编程,也不成问题。
我们希望您的编译器版本和标准尽可能的高,我们的代码均会测试三大编译器 gcc、clang、msvc。需要更高的标准会进行强调。
+
+
+
+
+
+如果你觉得本仓库对你有所帮助,可以通过支付宝赞助白老师,激励白老师有更多的精力和信心维护本仓库。
+
+
+
+> [!TIP]
+> 每一位开发者赞助 `30`,白老师一天的食品安全就有了着落。
+
+
diff --git a/SUMMARY.md b/SUMMARY.md
deleted file mode 100644
index cb06bc84..00000000
--- a/SUMMARY.md
+++ /dev/null
@@ -1,14 +0,0 @@
-# Summary
-
-* [首页](README.md)
-* [阅读须知](md/README.md)
-* [基本概念](md/01基本概念.md)
-* [使用线程](md/02使用线程.md)
-* [共享数据](md/03共享数据.md)
-* [同步操作](md/04同步操作.md)
-* [内存模型与原子操作](md/05内存模型与原子操作.md)
-* [协程](md/06协程.md)
-* [详细分析](md/详细分析/README.md)
- * [`std::thread` 的构造-源码解析](md/详细分析/01thread的构造与源码解析.md)
- * [`std::scoped_lock` 的源码实现与解析](md/详细分析/02scoped_lock源码解析.md)
- * [`std::async` 与 `std::future` 源码解析](md/详细分析/03async与future源码解析.md)
diff --git "a/code/04\345\220\214\346\255\245\346\223\215\344\275\234/async_progress_bar/async_progress_bar.h" "b/code/04\345\220\214\346\255\245\346\223\215\344\275\234/async_progress_bar/async_progress_bar.h"
index f97b0ac9..c3f43d3f 100644
--- "a/code/04\345\220\214\346\255\245\346\223\215\344\275\234/async_progress_bar/async_progress_bar.h"
+++ "b/code/04\345\220\214\346\255\245\346\223\215\344\275\234/async_progress_bar/async_progress_bar.h"
@@ -67,5 +67,5 @@ class async_progress_bar : public QMainWindow{
QPushButton* button{};
QPushButton* button2{};
Ui::async_progress_barClass ui{};
- std::futurefuture;
+ std::future future;
};
diff --git a/code/ModernCpp-ConcurrentProgramming-Tutorial/01-HelloWorld.cpp b/code/ModernCpp-ConcurrentProgramming-Tutorial/01-HelloWorld.cpp
new file mode 100644
index 00000000..3fbaabd8
--- /dev/null
+++ b/code/ModernCpp-ConcurrentProgramming-Tutorial/01-HelloWorld.cpp
@@ -0,0 +1,13 @@
+#include
+#include
+#include
+
+void hello(){
+ std::cout << "Hello World" << std::endl;
+ // std::this_thread::sleep_for(std::chrono::seconds(5));
+}
+
+int main(){
+ std::thread t; // 默认构造?构造不关联线程的 thread 对象
+ std::cout <
+#include
+#include
+#include
+#include
+#include
+
+template
+auto sum(ForwardIt first, ForwardIt last) {
+ using value_type = std::iter_value_t;
+ std::size_t num_threads = std::thread::hardware_concurrency();
+ std::ptrdiff_t distance = std::distance(first, last);
+
+ if (distance > 1024000) {
+ // 计算每个线程处理的元素数量
+ std::size_t chunk_size = distance / num_threads;
+ std::size_t remainder = distance % num_threads;
+
+ // 存储每个线程的结果
+ std::vector results{ num_threads };
+
+ // 存储关联线程的线程对象
+ std::vector threads;
+
+ // 创建并启动线程
+ auto start = first;
+ for (std::size_t i = 0; i < num_threads; ++i) {
+ auto end = std::next(start, chunk_size + (i < remainder ? 1 : 0));
+ threads.emplace_back([start, end, &results, i] {
+ results[i] = std::accumulate(start, end, value_type{});
+ });
+ start = end; // 开始迭代器不断向前
+ }
+
+ // 等待所有线程执行完毕
+ for (auto& thread : threads)
+ thread.join();
+
+ // 汇总线程的计算结果
+ value_type total_sum = std::accumulate(results.begin(), results.end(), value_type{});
+ return total_sum;
+ }
+
+ value_type total_sum = std::accumulate(first, last, value_type{});
+ return total_sum;
+}
+
+int main() {
+ std::vector vecs{ "1","2","3","4" };
+ auto result = sum(vecs.begin(), vecs.end());
+ std::cout << result << '\n';
+
+ vecs.clear();
+ for (std::size_t i = 0; i <= 1024001u; ++i) {
+ vecs.push_back(std::to_string(i));
+ }
+ result = sum(vecs.begin(), vecs.end());
+ std::cout << result << '\n';
+}
\ No newline at end of file
diff --git a/code/ModernCpp-ConcurrentProgramming-Tutorial/03-thread_management.cpp b/code/ModernCpp-ConcurrentProgramming-Tutorial/03-thread_management.cpp
new file mode 100644
index 00000000..0a9f1371
--- /dev/null
+++ b/code/ModernCpp-ConcurrentProgramming-Tutorial/03-thread_management.cpp
@@ -0,0 +1,32 @@
+#include
+#include
+
+struct func {
+ int& m_i;
+ func(int& i) :m_i{ i } {}
+ void operator()(int n)const {
+ for (int i = 0; i <= n; ++i) {
+ m_i += i; // 可能悬空引用
+ }
+ }
+};
+
+void f2() { throw std::runtime_error("test f2()"); }
+
+void f() {
+ int n = 0;
+ std::thread t{ func{n},10 };
+ try {
+ // todo.. 一些当前线程可能抛出异常的代码
+ f2();
+ t.join();
+ }
+ catch (...) {
+ t.join(); // 1
+ // 如果此处不抛出 会掩盖错误 我们根本没有处理 没有解决
+ }
+}
+
+int main() {
+ f();
+}
\ No newline at end of file
diff --git a/code/ModernCpp-ConcurrentProgramming-Tutorial/04-RAII.cpp b/code/ModernCpp-ConcurrentProgramming-Tutorial/04-RAII.cpp
new file mode 100644
index 00000000..e3e793af
--- /dev/null
+++ b/code/ModernCpp-ConcurrentProgramming-Tutorial/04-RAII.cpp
@@ -0,0 +1,48 @@
+#include
+#include
+#include
+
+struct func {
+ int& m_i;
+ func(int& i) :m_i{ i } {}
+ void operator()(int n)const {
+ for (int i = 0; i <= n; ++i) {
+ m_i += i; // 可能悬空引用
+ }
+ }
+};
+
+void f2(){
+ // todo..
+ throw std::runtime_error("f2 error");
+}
+
+class thread_guard{
+public:
+ explicit thread_guard(std::thread& t) :thread_{ t }
+ {}
+ ~thread_guard(){
+ std::puts("析构");
+ if(thread_.joinable()){ // 如果当前有活跃线程 则进行 join
+ thread_.join();
+ }
+ }
+ thread_guard& operator=(const thread_guard&) = delete;
+ thread_guard(const thread_guard&) = delete;
+
+ std::thread& thread_;
+};
+
+void f() {
+ int n = 0;
+ std::thread t{ func{n},10 };
+ thread_guard g(t);
+ f2(); // 可能抛出异常
+}
+
+int main(){
+ // 栈回溯
+ try{
+ f();
+ }catch (...){}
+}
\ No newline at end of file
diff --git "a/code/ModernCpp-ConcurrentProgramming-Tutorial/05-\344\274\240\351\200\222\345\217\202\346\225\260.cpp" "b/code/ModernCpp-ConcurrentProgramming-Tutorial/05-\344\274\240\351\200\222\345\217\202\346\225\260.cpp"
new file mode 100644
index 00000000..1ae06177
--- /dev/null
+++ "b/code/ModernCpp-ConcurrentProgramming-Tutorial/05-\344\274\240\351\200\222\345\217\202\346\225\260.cpp"
@@ -0,0 +1,20 @@
+#include
+#include
+#include
+
+void f(const std::string&);
+
+void test() {
+ char buffer[1024]{};
+ //todo.. code
+ std::thread t{ f, std::string(buffer) }; // std::string(buffer) 构造对象,由 std::string 对象自行管理
+ t.detach();
+}
+
+int main(){
+ // A 的引用只能引用 A 类型,或者以任何形式 转换到 A
+ double a = 1;
+ const int& p = a; // a 隐式转换到了 int 类型,这个转换是纯右值表达式
+ // 因为 const T& 可以接右值表达式,所以才能通过编译
+ const std::string& s = "123"; // "123" 构造了 std::string 对象
+}
\ No newline at end of file
diff --git "a/code/ModernCpp-ConcurrentProgramming-Tutorial/06-this_thread\345\221\275\345\220\215\347\251\272\351\227\264.cpp" "b/code/ModernCpp-ConcurrentProgramming-Tutorial/06-this_thread\345\221\275\345\220\215\347\251\272\351\227\264.cpp"
new file mode 100644
index 00000000..b99567e7
--- /dev/null
+++ "b/code/ModernCpp-ConcurrentProgramming-Tutorial/06-this_thread\345\221\275\345\220\215\347\251\272\351\227\264.cpp"
@@ -0,0 +1,28 @@
+#include
+#include
+#include
+using namespace std::chrono_literals;
+
+int main() {
+ // 获取当前时间点
+ auto now = std::chrono::system_clock::now();
+
+ // 设置要等待的时间点为当前时间点之后的5秒
+ auto wakeup_time = now + 5s;
+
+ // 输出当前时间
+ auto now_time = std::chrono::system_clock::to_time_t(now);
+ std::cout << "Current time:\t\t" << std::put_time(std::localtime(&now_time), "%H:%M:%S") << std::endl;
+
+ // 输出等待的时间点
+ auto wakeup_time_time = std::chrono::system_clock::to_time_t(wakeup_time);
+ std::cout << "Waiting until:\t\t" << std::put_time(std::localtime(&wakeup_time_time), "%H:%M:%S") << std::endl;
+
+ // 等待到指定的时间点
+ std::this_thread::sleep_until(wakeup_time);
+
+ // 输出等待结束后的时间
+ now = std::chrono::system_clock::now();
+ now_time = std::chrono::system_clock::to_time_t(now);
+ std::cout << "Time after waiting:\t" << std::put_time(std::localtime(&now_time), "%H:%M:%S") << std::endl;
+}
\ No newline at end of file
diff --git "a/code/ModernCpp-ConcurrentProgramming-Tutorial/07-thread\345\257\271\350\261\241\350\275\254\347\247\273\346\211\200\346\234\211\346\235\203.cpp" "b/code/ModernCpp-ConcurrentProgramming-Tutorial/07-thread\345\257\271\350\261\241\350\275\254\347\247\273\346\211\200\346\234\211\346\235\203.cpp"
new file mode 100644
index 00000000..3d7d267a
--- /dev/null
+++ "b/code/ModernCpp-ConcurrentProgramming-Tutorial/07-thread\345\257\271\350\261\241\350\275\254\347\247\273\346\211\200\346\234\211\346\235\203.cpp"
@@ -0,0 +1,18 @@
+#include
+#include
+
+// https://github.com/Mq-b/Loser-HomeWork/discussions/206
+
+// 反直觉
+// 形参、实参
+// 函数调用传参,实际上是初始化了(构造)形参的对象
+
+void f(std::thread t) {
+ t.join();
+}
+
+int main() {
+ std::thread t{ [] {} };
+ f(std::move(t));
+ f(std::thread{ [] {} });
+}
\ No newline at end of file
diff --git "a/code/ModernCpp-ConcurrentProgramming-Tutorial/08-thread\346\236\204\351\200\240\346\272\220\347\240\201\350\247\243\346\236\220.cpp" "b/code/ModernCpp-ConcurrentProgramming-Tutorial/08-thread\346\236\204\351\200\240\346\272\220\347\240\201\350\247\243\346\236\220.cpp"
new file mode 100644
index 00000000..691290ef
--- /dev/null
+++ "b/code/ModernCpp-ConcurrentProgramming-Tutorial/08-thread\346\236\204\351\200\240\346\272\220\347\240\201\350\247\243\346\236\220.cpp"
@@ -0,0 +1,16 @@
+#include
+#include
+#include
+
+struct X {
+ X(X&& x)noexcept {}
+ template , X>, int> = 0>
+ X(Fn&& f, Args&&...args) {}
+ X(const X&) = delete;
+};
+
+int main(){
+ std::thread
+ X x{ [] {} };
+ X x2{ x }; // 选择到了有参构造函数,不导致编译错误
+}
\ No newline at end of file
diff --git "a/code/ModernCpp-ConcurrentProgramming-Tutorial/09-\345\256\236\347\216\260joining_thread.cpp" "b/code/ModernCpp-ConcurrentProgramming-Tutorial/09-\345\256\236\347\216\260joining_thread.cpp"
new file mode 100644
index 00000000..ec488654
--- /dev/null
+++ "b/code/ModernCpp-ConcurrentProgramming-Tutorial/09-\345\256\236\347\216\260joining_thread.cpp"
@@ -0,0 +1,69 @@
+#include
+#include
+#include
+#include
+#include
+
+class joining_thread {
+ std::thread t;
+public:
+ joining_thread()noexcept = default;
+
+ template
+ explicit joining_thread(Callable&& func, Args&&...args) :
+ t{ std::forward(func), std::forward(args)... } {}
+
+ explicit joining_thread(std::thread t_)noexcept : t{ std::move(t_) } {}
+
+ joining_thread(joining_thread&& other)noexcept : t{ std::move(other.t) } {}
+
+ joining_thread& operator=(std::thread&& other)noexcept {
+ if (joinable()) { // 如果当前有活跃线程(判断当前对象是否持有资源),那就先执行完(先释放)
+ join(); // 就相当于释放资源一样的意思
+ }
+ t = std::move(other);
+ return *this;
+ }
+ ~joining_thread() {
+ if (joinable()) {
+ join();
+ }
+ }
+ void swap(joining_thread& other)noexcept {
+ t.swap(other.t);
+ }
+ std::thread::id get_id()const noexcept {
+ return t.get_id();
+ }
+ bool joinable()const noexcept {
+ return t.joinable();
+ }
+ void join() {
+ t.join();
+ }
+ void detach() {
+ t.detach();
+ }
+ std::thread& data()noexcept {
+ return t;
+ }
+ const std::thread& data()const noexcept {
+ return t;
+ }
+};
+
+int main(){
+ auto func = []{
+ std::cout << std::this_thread::get_id() << '\n';
+ };
+
+ std::vector vec;
+
+ for (int i = 0; i < 10; ++i){
+ vec.emplace_back(func);
+ }
+
+ for(auto& thread : vec){
+ thread.join();
+ }
+}
\ No newline at end of file
diff --git a/code/ModernCpp-ConcurrentProgramming-Tutorial/10-C++20jthread.cpp b/code/ModernCpp-ConcurrentProgramming-Tutorial/10-C++20jthread.cpp
new file mode 100644
index 00000000..308b281f
--- /dev/null
+++ b/code/ModernCpp-ConcurrentProgramming-Tutorial/10-C++20jthread.cpp
@@ -0,0 +1,20 @@
+#include
+#include
+
+using namespace std::literals::chrono_literals;
+
+void f(std::stop_token stop_token, int value) {
+ while (!stop_token.stop_requested()) { // 检查是否已经收到停止请求
+ std::cout << value++ << ' ' << std::flush;
+ std::this_thread::sleep_for(200ms);
+ }
+ std::cout << std::endl;
+}
+
+int main() {
+ std::jthread thread{ f, 1 }; // 打印 1..15 大约 3 秒
+ std::this_thread::sleep_for(3s);
+ thread.request_stop(); // 发送信息,线程终止
+ std::cout << "乐\n";
+ // jthread 的析构函数调用 request_stop() 和 join()。
+}
\ No newline at end of file
diff --git "a/code/ModernCpp-ConcurrentProgramming-Tutorial/11-\346\225\260\346\215\256\347\253\236\344\272\211.cpp" "b/code/ModernCpp-ConcurrentProgramming-Tutorial/11-\346\225\260\346\215\256\347\253\236\344\272\211.cpp"
new file mode 100644
index 00000000..5607d6c6
--- /dev/null
+++ "b/code/ModernCpp-ConcurrentProgramming-Tutorial/11-\346\225\260\346\215\256\347\253\236\344\272\211.cpp"
@@ -0,0 +1,19 @@
+#include
+#include
+#include
+
+std::vector v;
+
+int n = 1;
+
+int main() {
+ int cnt = 0;
+ auto f = [&] { cnt++; };
+ std::thread t1{ f }, t2{ f }, t3{ f }; // ub 未定义行为
+ t1.join();
+ t2.join();
+ t3.join();
+ std::cout << cnt << '\n';
+}
+// 数据竞争它是未定义行为,但是 C++ 的编译器,它会假设你的程序(假设程序是对的,代码是对的)没有任何的未定义行为再去进行优化
+// 输出 n,优化,直接缓存这个值
\ No newline at end of file
diff --git "a/code/ModernCpp-ConcurrentProgramming-Tutorial/12-\344\275\277\347\224\250\344\272\222\346\226\245\351\207\217.cpp" "b/code/ModernCpp-ConcurrentProgramming-Tutorial/12-\344\275\277\347\224\250\344\272\222\346\226\245\351\207\217.cpp"
new file mode 100644
index 00000000..534d2410
--- /dev/null
+++ "b/code/ModernCpp-ConcurrentProgramming-Tutorial/12-\344\275\277\347\224\250\344\272\222\346\226\245\351\207\217.cpp"
@@ -0,0 +1,44 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+std::mutex m;
+
+// 写
+void add_to_list(int n, std::list& list) {
+ std::vector numbers(n + 1);
+ std::iota(numbers.begin(), numbers.end(), 0);
+ int sum = std::accumulate(numbers.begin(), numbers.end(), 0);
+
+ {
+ std::scoped_lock lc{ m };
+ list.push_back(sum);
+ }
+}
+
+// 读
+void print_list(const std::list& list) {
+ std::scoped_lock lc{ m };
+ for (const auto& i : list) {
+ std::cout << i << ' ';
+ }
+ std::cout << '\n';
+}
+
+int main(){
+ std::list list;
+ std::thread t1{ add_to_list,10,std::ref(list) };
+ std::thread t2{ add_to_list,10,std::ref(list) };
+ std::thread t3{ print_list,std::cref(list) };
+ std::thread t4{ print_list,std::cref(list) };
+ t1.join();
+ t2.join();
+ t3.join();
+ t4.join();
+ std::cout << "---------------------\n";
+ print_list(list);
+}
\ No newline at end of file
diff --git a/code/ModernCpp-ConcurrentProgramming-Tutorial/13-try_lock.cpp b/code/ModernCpp-ConcurrentProgramming-Tutorial/13-try_lock.cpp
new file mode 100644
index 00000000..fcbbf365
--- /dev/null
+++ b/code/ModernCpp-ConcurrentProgramming-Tutorial/13-try_lock.cpp
@@ -0,0 +1,33 @@
+#include
+#include
+#include
+#include
+#include
+using namespace std::string_literals;
+
+std::mutex mtx;
+
+void thread_function(int id) {
+ // 尝试加锁
+ if (mtx.try_lock()) {
+ std::string s = "线程:"s + std::to_string(id) + " 获得锁"s + "\n";
+ std::string s2 = "线程:"s + std::to_string(id) + " 释放锁"s + "\n";
+ std::cout << s;
+ // 临界区代码
+ std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟临界区操作
+ mtx.unlock(); // 解锁
+ std::cout << s2;
+ }
+ else {
+ std::string s = "线程:"s + std::to_string(id) + " 获取锁失败 处理步骤"s + "\n";
+ std::cout << s;
+ }
+}
+
+int main(){
+ std::thread t1(thread_function, 1);
+ std::thread t2(thread_function, 2);
+
+ t1.join();
+ t2.join();
+}
\ No newline at end of file
diff --git "a/code/ModernCpp-ConcurrentProgramming-Tutorial/14-\344\277\235\346\212\244\345\205\261\344\272\253\346\225\260\346\215\256.cpp" "b/code/ModernCpp-ConcurrentProgramming-Tutorial/14-\344\277\235\346\212\244\345\205\261\344\272\253\346\225\260\346\215\256.cpp"
new file mode 100644
index 00000000..d93d694d
--- /dev/null
+++ "b/code/ModernCpp-ConcurrentProgramming-Tutorial/14-\344\277\235\346\212\244\345\205\261\344\272\253\346\225\260\346\215\256.cpp"
@@ -0,0 +1,40 @@
+#include
+#include
+#include
+
+class Data {
+ int a{};
+ std::string b{};
+public:
+ void do_something() {
+ // 修改数据成员等...
+ }
+};
+
+class Data_wrapper {
+ Data data;
+ std::mutex m;
+public:
+ template
+ void process_data(Func func) {
+ std::lock_guard lc{ m };
+ func(data); // 受保护数据传递给函数
+ }
+};
+
+Data* p = nullptr;
+
+void malicious_function(Data& protected_data) {
+ p = &protected_data; // 受保护的数据被传递到外部
+}
+
+Data_wrapper d;
+
+void foo() {
+ d.process_data(malicious_function); // 传递了一个恶意的函数
+ p->do_something(); // 在无保护的情况下访问保护数据
+}
+
+int main(){
+
+}
\ No newline at end of file
diff --git "a/code/ModernCpp-ConcurrentProgramming-Tutorial/15-\346\255\273\351\224\201\357\274\232\351\227\256\351\242\230\344\270\216\350\247\243\345\206\263.cpp" "b/code/ModernCpp-ConcurrentProgramming-Tutorial/15-\346\255\273\351\224\201\357\274\232\351\227\256\351\242\230\344\270\216\350\247\243\345\206\263.cpp"
new file mode 100644
index 00000000..dd22b6e2
--- /dev/null
+++ "b/code/ModernCpp-ConcurrentProgramming-Tutorial/15-\346\255\273\351\224\201\357\274\232\351\227\256\351\242\230\344\270\216\350\247\243\345\206\263.cpp"
@@ -0,0 +1,28 @@
+#include
+#include
+#include
+#include
+using namespace std::chrono_literals;
+
+struct X {
+ X(const std::string& str) :object{ str } {}
+
+ friend void swap(X& lhs, X& rhs);
+private:
+ std::string object;
+ std::mutex m;
+};
+
+void swap(X& lhs, X& rhs) {
+ if (&lhs == &rhs) return;
+ std::scoped_lock guard{ lhs.m,rhs.m };
+ swap(lhs.object, rhs.object);
+}
+
+int main(){
+ X a{ "🤣" }, b{ "😅" };
+ std::thread t{ [&] {swap(a, b); } }; // 1
+ std::thread t2{ [&] {swap(b, a); } }; // 2
+ t.join();
+ t2.join();
+}
\ No newline at end of file
diff --git a/code/ModernCpp-ConcurrentProgramming-Tutorial/16-unique_lock.cpp b/code/ModernCpp-ConcurrentProgramming-Tutorial/16-unique_lock.cpp
new file mode 100644
index 00000000..74e32db7
--- /dev/null
+++ b/code/ModernCpp-ConcurrentProgramming-Tutorial/16-unique_lock.cpp
@@ -0,0 +1,32 @@
+#include
+#include
+#include
+#include
+using namespace std::chrono_literals;
+
+struct X {
+ X(const std::string& str) :object{ str } {}
+
+ friend void swap(X& lhs, X& rhs);
+private:
+ std::string object;
+ std::mutex m;
+};
+
+void swap(X& lhs, X& rhs) {
+ if (&lhs == &rhs) return;
+ std::lock(rhs.m, lhs.m);
+
+ std::unique_lock lock1{ lhs.m, std::adopt_lock };
+ std::unique_lock lock2{ rhs.m, std::adopt_lock };
+ // std::lock(lock1, lock2);
+ swap(lhs.object, rhs.object);
+}
+
+int main() {
+ X a{ "🤣" }, b{ "😅" };
+ std::thread t{ [&] {swap(a, b); } }; // 1
+ std::thread t2{ [&] {swap(b, a); } }; // 2
+ t.join();
+ t2.join();
+}
\ No newline at end of file
diff --git "a/code/ModernCpp-ConcurrentProgramming-Tutorial/17-\345\234\250\344\270\215\345\220\214\344\275\234\347\224\250\345\237\237\344\274\240\351\200\222\344\272\222\346\226\245\351\207\217.cpp" "b/code/ModernCpp-ConcurrentProgramming-Tutorial/17-\345\234\250\344\270\215\345\220\214\344\275\234\347\224\250\345\237\237\344\274\240\351\200\222\344\272\222\346\226\245\351\207\217.cpp"
new file mode 100644
index 00000000..dbe08886
--- /dev/null
+++ "b/code/ModernCpp-ConcurrentProgramming-Tutorial/17-\345\234\250\344\270\215\345\220\214\344\275\234\347\224\250\345\237\237\344\274\240\351\200\222\344\272\222\346\226\245\351\207\217.cpp"
@@ -0,0 +1,19 @@
+#include
+#include
+#include
+#include
+#include
+
+std::unique_lock get_lock() {
+ extern std::mutex some_mutex;
+ std::unique_lock lk{ some_mutex };
+ return lk; // 选择到 unique_lock 的移动构造,转移所有权
+}
+void process_data() {
+ std::unique_lock lk{ get_lock() }; // 转移到了主函数的 lk 中
+ // 执行一些任务...
+}// 最后才会 unlock 解锁
+
+int main(){
+ process_data();
+}
\ No newline at end of file
diff --git "a/code/ModernCpp-ConcurrentProgramming-Tutorial/18-\344\277\235\346\212\244\345\205\261\344\272\253\346\225\260\346\215\256\347\232\204\345\210\235\345\247\213\345\214\226\350\277\207\347\250\213.cpp" "b/code/ModernCpp-ConcurrentProgramming-Tutorial/18-\344\277\235\346\212\244\345\205\261\344\272\253\346\225\260\346\215\256\347\232\204\345\210\235\345\247\213\345\214\226\350\277\207\347\250\213.cpp"
new file mode 100644
index 00000000..8b19028c
--- /dev/null
+++ "b/code/ModernCpp-ConcurrentProgramming-Tutorial/18-\344\277\235\346\212\244\345\205\261\344\272\253\346\225\260\346\215\256\347\232\204\345\210\235\345\247\213\345\214\226\350\277\207\347\250\213.cpp"
@@ -0,0 +1,51 @@
+#include
+#include
+#include
+#include
+#include
+
+struct some{
+ void do_something(){}
+};
+
+std::shared_ptr ptr;
+std::once_flag resource_flag;
+
+void init_resource() {
+ ptr.reset(new some);
+}
+
+void foo() {
+ std::call_once(resource_flag, []{ptr.reset(new some); }); // 线程安全的一次初始化
+ ptr->do_something();
+}
+
+void test(){
+ std::call_once(resource_flag, [] {std::cout << "f init\n"; });
+}
+
+std::once_flag flag;
+int n = 0;
+
+void f() {
+ std::call_once(flag, [] {
+ ++n;
+ std::cout << "第 " << n << " 次调用\n";
+ throw std::runtime_error("异常");
+ });
+}
+
+class my_class{};
+
+inline my_class& get_my_class_instance() {
+ static my_class instance; // 线程安全的初始化过程 初始化严格发生一次
+ return instance;
+}
+
+int main() {
+ get_my_class_instance();
+ get_my_class_instance();
+ get_my_class_instance();
+ get_my_class_instance();
+ get_my_class_instance();
+}
\ No newline at end of file
diff --git "a/code/ModernCpp-ConcurrentProgramming-Tutorial/19\344\277\235\346\212\244\344\270\215\345\270\270\346\233\264\346\226\260\347\232\204\346\225\260\346\215\256\347\273\223\346\236\204.cpp" "b/code/ModernCpp-ConcurrentProgramming-Tutorial/19\344\277\235\346\212\244\344\270\215\345\270\270\346\233\264\346\226\260\347\232\204\346\225\260\346\215\256\347\273\223\346\236\204.cpp"
new file mode 100644
index 00000000..135048b8
--- /dev/null
+++ "b/code/ModernCpp-ConcurrentProgramming-Tutorial/19\344\277\235\346\212\244\344\270\215\345\270\270\346\233\264\346\226\260\347\232\204\346\225\260\346\215\256\347\273\223\346\236\204.cpp"
@@ -0,0 +1,47 @@
+#include
+#include
+#include
+#include
+#include