-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1. 修改第二、第三章的部分微小措辞以及代码格式。 2. 更新项目文件中的代码示例,用作视频学习。
- Loading branch information
Showing
16 changed files
with
436 additions
and
13 deletions.
There are no files selected for viewing
69 changes: 69 additions & 0 deletions
69
code/ModernCpp-ConcurrentProgramming-Tutorial/09-实现joining_thread.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
#include <iostream> | ||
#include <thread> | ||
#include <type_traits> | ||
#include <vector> | ||
#include <mutex> | ||
|
||
class joining_thread { | ||
std::thread t; | ||
public: | ||
joining_thread()noexcept = default; | ||
|
||
template<typename Callable, typename... Args> | ||
explicit joining_thread(Callable&& func, Args&&...args) : | ||
t{ std::forward<Callable>(func), std::forward<Args>(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<std::thread> vec; | ||
|
||
for (int i = 0; i < 10; ++i){ | ||
vec.emplace_back(func); | ||
} | ||
|
||
for(auto& thread : vec){ | ||
thread.join(); | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
code/ModernCpp-ConcurrentProgramming-Tutorial/10-C++20jthread.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#include <iostream> | ||
#include <thread> | ||
|
||
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()。 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#include <iostream> | ||
#include <thread> | ||
#include <vector> | ||
|
||
std::vector<int> 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,优化,直接缓存这个值 |
44 changes: 44 additions & 0 deletions
44
code/ModernCpp-ConcurrentProgramming-Tutorial/12-使用互斥量.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#include <iostream> | ||
#include <thread> | ||
#include <vector> | ||
#include <mutex> | ||
#include <algorithm> | ||
#include <list> | ||
#include <numeric> | ||
|
||
std::mutex m; | ||
|
||
// 写 | ||
void add_to_list(int n, std::list<int>& list) { | ||
std::vector<int> 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<int>& list) { | ||
std::scoped_lock lc{ m }; | ||
for (const auto& i : list) { | ||
std::cout << i << ' '; | ||
} | ||
std::cout << '\n'; | ||
} | ||
|
||
int main(){ | ||
std::list<int> 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); | ||
} |
33 changes: 33 additions & 0 deletions
33
code/ModernCpp-ConcurrentProgramming-Tutorial/13-try_lock.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#include <iostream> | ||
#include <thread> | ||
#include <vector> | ||
#include <mutex> | ||
#include <string> | ||
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(); | ||
} |
40 changes: 40 additions & 0 deletions
40
code/ModernCpp-ConcurrentProgramming-Tutorial/14-保护共享数据.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#include <iostream> | ||
#include <thread> | ||
#include <mutex> | ||
|
||
class Data { | ||
int a{}; | ||
std::string b{}; | ||
public: | ||
void do_something() { | ||
// 修改数据成员等... | ||
} | ||
}; | ||
|
||
class Data_wrapper { | ||
Data data; | ||
std::mutex m; | ||
public: | ||
template<class Func> | ||
void process_data(Func func) { | ||
std::lock_guard<std::mutex> 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(){ | ||
|
||
} |
28 changes: 28 additions & 0 deletions
28
code/ModernCpp-ConcurrentProgramming-Tutorial/15-死锁:问题与解决.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#include <iostream> | ||
#include <thread> | ||
#include <mutex> | ||
#include <chrono> | ||
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(); | ||
} |
32 changes: 32 additions & 0 deletions
32
code/ModernCpp-ConcurrentProgramming-Tutorial/16-unique_lock.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#include <iostream> | ||
#include <thread> | ||
#include <mutex> | ||
#include <chrono> | ||
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<std::mutex> lock1{ lhs.m, std::adopt_lock }; | ||
std::unique_lock<std::mutex> 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(); | ||
} |
19 changes: 19 additions & 0 deletions
19
code/ModernCpp-ConcurrentProgramming-Tutorial/17-在不同作用域传递互斥量.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#include <iostream> | ||
#include <thread> | ||
#include <mutex> | ||
#include <chrono> | ||
#include <memory> | ||
|
||
std::unique_lock<std::mutex> get_lock() { | ||
extern std::mutex some_mutex; | ||
std::unique_lock<std::mutex> lk{ some_mutex }; | ||
return lk; // 选择到 unique_lock 的移动构造,转移所有权 | ||
} | ||
void process_data() { | ||
std::unique_lock<std::mutex> lk{ get_lock() }; // 转移到了主函数的 lk 中 | ||
// 执行一些任务... | ||
}// 最后才会 unlock 解锁 | ||
|
||
int main(){ | ||
process_data(); | ||
} |
51 changes: 51 additions & 0 deletions
51
code/ModernCpp-ConcurrentProgramming-Tutorial/18-保护共享数据的初始化过程.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
#include <iostream> | ||
#include <thread> | ||
#include <mutex> | ||
#include <chrono> | ||
#include <memory> | ||
|
||
struct some{ | ||
void do_something(){} | ||
}; | ||
|
||
std::shared_ptr<some> 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(); | ||
} |
Oops, something went wrong.