Skip to content

Commit

Permalink
更新教案
Browse files Browse the repository at this point in the history
1. 修改第二、第三章的部分微小措辞以及代码格式。
2. 更新项目文件中的代码示例,用作视频学习。
  • Loading branch information
Mq-b committed Sep 17, 2024
1 parent 4f43473 commit 79952e4
Show file tree
Hide file tree
Showing 16 changed files with 436 additions and 13 deletions.
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 code/ModernCpp-ConcurrentProgramming-Tutorial/10-C++20jthread.cpp
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()。
}
19 changes: 19 additions & 0 deletions code/ModernCpp-ConcurrentProgramming-Tutorial/11-数据竞争.cpp
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,优化,直接缓存这个值
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 code/ModernCpp-ConcurrentProgramming-Tutorial/13-try_lock.cpp
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();
}
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(){

}
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 code/ModernCpp-ConcurrentProgramming-Tutorial/16-unique_lock.cpp
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();
}
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();
}
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();
}
Loading

0 comments on commit 79952e4

Please sign in to comment.