Skip to content

Commit 79952e4

Browse files
committed
更新教案
1. 修改第二、第三章的部分微小措辞以及代码格式。 2. 更新项目文件中的代码示例,用作视频学习。
1 parent 4f43473 commit 79952e4

16 files changed

+436
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#include <iostream>
2+
#include <thread>
3+
#include <type_traits>
4+
#include <vector>
5+
#include <mutex>
6+
7+
class joining_thread {
8+
std::thread t;
9+
public:
10+
joining_thread()noexcept = default;
11+
12+
template<typename Callable, typename... Args>
13+
explicit joining_thread(Callable&& func, Args&&...args) :
14+
t{ std::forward<Callable>(func), std::forward<Args>(args)... } {}
15+
16+
explicit joining_thread(std::thread t_)noexcept : t{ std::move(t_) } {}
17+
18+
joining_thread(joining_thread&& other)noexcept : t{ std::move(other.t) } {}
19+
20+
joining_thread& operator=(std::thread&& other)noexcept {
21+
if (joinable()) { // 如果当前有活跃线程(判断当前对象是否持有资源),那就先执行完(先释放)
22+
join(); // 就相当于释放资源一样的意思
23+
}
24+
t = std::move(other);
25+
return *this;
26+
}
27+
~joining_thread() {
28+
if (joinable()) {
29+
join();
30+
}
31+
}
32+
void swap(joining_thread& other)noexcept {
33+
t.swap(other.t);
34+
}
35+
std::thread::id get_id()const noexcept {
36+
return t.get_id();
37+
}
38+
bool joinable()const noexcept {
39+
return t.joinable();
40+
}
41+
void join() {
42+
t.join();
43+
}
44+
void detach() {
45+
t.detach();
46+
}
47+
std::thread& data()noexcept {
48+
return t;
49+
}
50+
const std::thread& data()const noexcept {
51+
return t;
52+
}
53+
};
54+
55+
int main(){
56+
auto func = []{
57+
std::cout << std::this_thread::get_id() << '\n';
58+
};
59+
60+
std::vector<std::thread> vec;
61+
62+
for (int i = 0; i < 10; ++i){
63+
vec.emplace_back(func);
64+
}
65+
66+
for(auto& thread : vec){
67+
thread.join();
68+
}
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <iostream>
2+
#include <thread>
3+
4+
using namespace std::literals::chrono_literals;
5+
6+
void f(std::stop_token stop_token, int value) {
7+
while (!stop_token.stop_requested()) { // 检查是否已经收到停止请求
8+
std::cout << value++ << ' ' << std::flush;
9+
std::this_thread::sleep_for(200ms);
10+
}
11+
std::cout << std::endl;
12+
}
13+
14+
int main() {
15+
std::jthread thread{ f, 1 }; // 打印 1..15 大约 3 秒
16+
std::this_thread::sleep_for(3s);
17+
thread.request_stop(); // 发送信息,线程终止
18+
std::cout << "\n";
19+
// jthread 的析构函数调用 request_stop() 和 join()。
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <iostream>
2+
#include <thread>
3+
#include <vector>
4+
5+
std::vector<int> v;
6+
7+
int n = 1;
8+
9+
int main() {
10+
int cnt = 0;
11+
auto f = [&] { cnt++; };
12+
std::thread t1{ f }, t2{ f }, t3{ f }; // ub 未定义行为
13+
t1.join();
14+
t2.join();
15+
t3.join();
16+
std::cout << cnt << '\n';
17+
}
18+
// 数据竞争它是未定义行为,但是 C++ 的编译器,它会假设你的程序(假设程序是对的,代码是对的)没有任何的未定义行为再去进行优化
19+
// 输出 n,优化,直接缓存这个值
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#include <iostream>
2+
#include <thread>
3+
#include <vector>
4+
#include <mutex>
5+
#include <algorithm>
6+
#include <list>
7+
#include <numeric>
8+
9+
std::mutex m;
10+
11+
//
12+
void add_to_list(int n, std::list<int>& list) {
13+
std::vector<int> numbers(n + 1);
14+
std::iota(numbers.begin(), numbers.end(), 0);
15+
int sum = std::accumulate(numbers.begin(), numbers.end(), 0);
16+
17+
{
18+
std::scoped_lock lc{ m };
19+
list.push_back(sum);
20+
}
21+
}
22+
23+
//
24+
void print_list(const std::list<int>& list) {
25+
std::scoped_lock lc{ m };
26+
for (const auto& i : list) {
27+
std::cout << i << ' ';
28+
}
29+
std::cout << '\n';
30+
}
31+
32+
int main(){
33+
std::list<int> list;
34+
std::thread t1{ add_to_list,10,std::ref(list) };
35+
std::thread t2{ add_to_list,10,std::ref(list) };
36+
std::thread t3{ print_list,std::cref(list) };
37+
std::thread t4{ print_list,std::cref(list) };
38+
t1.join();
39+
t2.join();
40+
t3.join();
41+
t4.join();
42+
std::cout << "---------------------\n";
43+
print_list(list);
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include <iostream>
2+
#include <thread>
3+
#include <vector>
4+
#include <mutex>
5+
#include <string>
6+
using namespace std::string_literals;
7+
8+
std::mutex mtx;
9+
10+
void thread_function(int id) {
11+
// 尝试加锁
12+
if (mtx.try_lock()) {
13+
std::string s = "线程:"s + std::to_string(id) + " 获得锁"s + "\n";
14+
std::string s2 = "线程:"s + std::to_string(id) + " 释放锁"s + "\n";
15+
std::cout << s;
16+
// 临界区代码
17+
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟临界区操作
18+
mtx.unlock(); // 解锁
19+
std::cout << s2;
20+
}
21+
else {
22+
std::string s = "线程:"s + std::to_string(id) + " 获取锁失败 处理步骤"s + "\n";
23+
std::cout << s;
24+
}
25+
}
26+
27+
int main(){
28+
std::thread t1(thread_function, 1);
29+
std::thread t2(thread_function, 2);
30+
31+
t1.join();
32+
t2.join();
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <iostream>
2+
#include <thread>
3+
#include <mutex>
4+
5+
class Data {
6+
int a{};
7+
std::string b{};
8+
public:
9+
void do_something() {
10+
// 修改数据成员等...
11+
}
12+
};
13+
14+
class Data_wrapper {
15+
Data data;
16+
std::mutex m;
17+
public:
18+
template<class Func>
19+
void process_data(Func func) {
20+
std::lock_guard<std::mutex> lc{ m };
21+
func(data); // 受保护数据传递给函数
22+
}
23+
};
24+
25+
Data* p = nullptr;
26+
27+
void malicious_function(Data& protected_data) {
28+
p = &protected_data; // 受保护的数据被传递到外部
29+
}
30+
31+
Data_wrapper d;
32+
33+
void foo() {
34+
d.process_data(malicious_function); // 传递了一个恶意的函数
35+
p->do_something(); // 在无保护的情况下访问保护数据
36+
}
37+
38+
int main(){
39+
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <iostream>
2+
#include <thread>
3+
#include <mutex>
4+
#include <chrono>
5+
using namespace std::chrono_literals;
6+
7+
struct X {
8+
X(const std::string& str) :object{ str } {}
9+
10+
friend void swap(X& lhs, X& rhs);
11+
private:
12+
std::string object;
13+
std::mutex m;
14+
};
15+
16+
void swap(X& lhs, X& rhs) {
17+
if (&lhs == &rhs) return;
18+
std::scoped_lock guard{ lhs.m,rhs.m };
19+
swap(lhs.object, rhs.object);
20+
}
21+
22+
int main(){
23+
X a{ "🤣" }, b{ "😅" };
24+
std::thread t{ [&] {swap(a, b); } }; // 1
25+
std::thread t2{ [&] {swap(b, a); } }; // 2
26+
t.join();
27+
t2.join();
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include <iostream>
2+
#include <thread>
3+
#include <mutex>
4+
#include <chrono>
5+
using namespace std::chrono_literals;
6+
7+
struct X {
8+
X(const std::string& str) :object{ str } {}
9+
10+
friend void swap(X& lhs, X& rhs);
11+
private:
12+
std::string object;
13+
std::mutex m;
14+
};
15+
16+
void swap(X& lhs, X& rhs) {
17+
if (&lhs == &rhs) return;
18+
std::lock(rhs.m, lhs.m);
19+
20+
std::unique_lock<std::mutex> lock1{ lhs.m, std::adopt_lock };
21+
std::unique_lock<std::mutex> lock2{ rhs.m, std::adopt_lock };
22+
// std::lock(lock1, lock2);
23+
swap(lhs.object, rhs.object);
24+
}
25+
26+
int main() {
27+
X a{ "🤣" }, b{ "😅" };
28+
std::thread t{ [&] {swap(a, b); } }; // 1
29+
std::thread t2{ [&] {swap(b, a); } }; // 2
30+
t.join();
31+
t2.join();
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <iostream>
2+
#include <thread>
3+
#include <mutex>
4+
#include <chrono>
5+
#include <memory>
6+
7+
std::unique_lock<std::mutex> get_lock() {
8+
extern std::mutex some_mutex;
9+
std::unique_lock<std::mutex> lk{ some_mutex };
10+
return lk; // 选择到 unique_lock 的移动构造,转移所有权
11+
}
12+
void process_data() {
13+
std::unique_lock<std::mutex> lk{ get_lock() }; // 转移到了主函数的 lk 中
14+
// 执行一些任务...
15+
}// 最后才会 unlock 解锁
16+
17+
int main(){
18+
process_data();
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include <iostream>
2+
#include <thread>
3+
#include <mutex>
4+
#include <chrono>
5+
#include <memory>
6+
7+
struct some{
8+
void do_something(){}
9+
};
10+
11+
std::shared_ptr<some> ptr;
12+
std::once_flag resource_flag;
13+
14+
void init_resource() {
15+
ptr.reset(new some);
16+
}
17+
18+
void foo() {
19+
std::call_once(resource_flag, []{ptr.reset(new some); }); // 线程安全的一次初始化
20+
ptr->do_something();
21+
}
22+
23+
void test(){
24+
std::call_once(resource_flag, [] {std::cout << "f init\n"; });
25+
}
26+
27+
std::once_flag flag;
28+
int n = 0;
29+
30+
void f() {
31+
std::call_once(flag, [] {
32+
++n;
33+
std::cout << "" << n << " 次调用\n";
34+
throw std::runtime_error("异常");
35+
});
36+
}
37+
38+
class my_class{};
39+
40+
inline my_class& get_my_class_instance() {
41+
static my_class instance; // 线程安全的初始化过程 初始化严格发生一次
42+
return instance;
43+
}
44+
45+
int main() {
46+
get_my_class_instance();
47+
get_my_class_instance();
48+
get_my_class_instance();
49+
get_my_class_instance();
50+
get_my_class_instance();
51+
}

0 commit comments

Comments
 (0)