Skip to content

Commit 01aafde

Browse files
committed
更新视频代码
1 parent 7877d0e commit 01aafde

6 files changed

+176
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include <iostream>
2+
#include <atomic>
3+
#include <mutex>
4+
#include <thread>
5+
6+
class spinlock_mutex {
7+
std::atomic_flag flag{};
8+
public:
9+
spinlock_mutex()noexcept = default;
10+
void lock()noexcept {
11+
while (flag.test_and_set(std::memory_order_acquire));
12+
}
13+
14+
void unlock()noexcept {
15+
flag.clear(std::memory_order_release);
16+
}
17+
};
18+
19+
spinlock_mutex m;
20+
21+
void f() {
22+
std::lock_guard<spinlock_mutex> lc{ m };
23+
std::cout << "😅😅" << "❤️❤️\n";
24+
}
25+
26+
int main(){
27+
std::thread t{ f };
28+
std::thread t1{ f };
29+
std::thread t2{ f };
30+
std::thread t3{ f };
31+
std::thread t4{ f };
32+
std::thread t5{ f };
33+
t.join();
34+
t1.join();
35+
t2.join();
36+
t3.join();
37+
t4.join();
38+
t5.join();
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <atomic>
2+
#include <iostream>
3+
#include <thread>
4+
5+
std::atomic<bool> flag{ false };
6+
bool expected = false;
7+
8+
void try_set_flag() {
9+
// 尝试将 flag 设置为 true,如果当前值为 false
10+
if (flag.compare_exchange_strong(expected, true)) {
11+
std::cout << "flag 为 false,flag 设为 true。\n";
12+
}
13+
else {
14+
std::cout << "flag 为 true, expected 设为 true。\n";
15+
}
16+
}
17+
18+
int main() {
19+
std::thread t1{ try_set_flag };
20+
std::thread t2{ try_set_flag };
21+
t1.join();
22+
t2.join();
23+
std::cout << "flag: " << std::boolalpha << flag << '\n';
24+
std::cout << "expected: " << std::boolalpha << expected << '\n';
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include <iostream>
2+
3+
struct X{
4+
int v{};
5+
void f()const {
6+
std::cout << v << '\n';
7+
}
8+
};
9+
10+
int main(){
11+
int arr[10]{ 1,2 };
12+
13+
std::atomic<int*> p{ arr };
14+
15+
p.fetch_add(1);
16+
std::cout << *(p.load()) << '\n';
17+
18+
p.fetch_sub(1);
19+
std::cout << *(p.load()) << '\n';
20+
21+
p += 1;
22+
std::cout << *(p.load()) << '\n';
23+
24+
p -= 1;
25+
std::cout << *(p.load()) << '\n';
26+
27+
X xs[3]{ {10},{20},{30} };
28+
std::atomic<X*> p2{ xs };
29+
p2.load()->f();
30+
p2 += 2;
31+
p2.load()->f();
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include <iostream>
2+
#include <memory>
3+
#include <thread>
4+
#include <chrono>
5+
#include <syncstream>
6+
using namespace std::chrono_literals;
7+
8+
class Data {
9+
public:
10+
Data(int value = 0) : value_(value) {}
11+
int get_value() const { return value_; }
12+
void set_value(int new_value) { value_ = new_value; }
13+
private:
14+
int value_;
15+
};
16+
17+
std::atomic<std::shared_ptr<Data>> data = std::make_shared<Data>();
18+
19+
void writer() {
20+
for (int i = 0; i < 10; ++i) {
21+
std::shared_ptr<Data> new_data = std::make_shared<Data>(i);
22+
data.store(new_data);
23+
std::this_thread::sleep_for(100ms);
24+
}
25+
}
26+
27+
void reader() {
28+
for (int i = 0; i < 10; ++i) {
29+
if (auto sp = data.load()) {
30+
std::cout << "读取线程值: " << sp->get_value() << std::endl;
31+
}
32+
else {
33+
std::cout << "没有读取到数据" << std::endl;
34+
}
35+
std::this_thread::sleep_for(100ms);
36+
}
37+
}
38+
39+
std::atomic<std::shared_ptr<int>> ptr = std::make_shared<int>();
40+
41+
void wait_for_wake_up() {
42+
std::osyncstream{ std::cout }
43+
<< "线程 "
44+
<< std::this_thread::get_id()
45+
<< " 阻塞,等待更新唤醒\n";
46+
47+
// 等待 ptr 变为其它值
48+
ptr.wait(ptr.load());
49+
50+
std::osyncstream{ std::cout }
51+
<< "线程 "
52+
<< std::this_thread::get_id()
53+
<< " 已被唤醒\n";
54+
}
55+
56+
void wake_up() {
57+
std::this_thread::sleep_for(5s);
58+
59+
// 更新值并唤醒
60+
ptr.store(std::make_shared<int>(10));
61+
ptr.notify_one();
62+
}
63+
64+
int main() {
65+
//std::thread writer_thread{ writer };
66+
//std::thread reader_thread{ reader };
67+
68+
//writer_thread.join();
69+
//reader_thread.join();
70+
71+
//std::atomic<std::shared_ptr<int>> ptr = std::make_shared<int>(10);
72+
//std::atomic_ref<int> ref{ *ptr.load() };
73+
//ref = 100; // 原子地赋 100 给被引用的对象
74+
//std::cout << *ptr.load() << '\n';
75+
std::thread t1{ wait_for_wake_up };
76+
wake_up();
77+
t1.join();
78+
}

code/ModernCpp-ConcurrentProgramming-Tutorial/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "C
1212
add_compile_options("-finput-charset=UTF-8" "-fexec-charset=UTF-8" "-fopenmp")
1313
endif()
1414

15-
add_executable(${PROJECT_NAME} "41实现一个线程池.cpp")
15+
add_executable(${PROJECT_NAME} "45原子特化shared_ptr.cpp")
1616

1717
set(SFML_DIR "D:/lib/SFML-2.6.1-windows-vc17-64-bit/SFML-2.6.1/lib/cmake/SFML")
1818
find_package(SFML 2.6.1 COMPONENTS system window graphics audio network REQUIRED)

md/05内存模型与原子操作.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ void f(){
311311
312312
稍微聊一下原理,我们的 `spinlock_mutex` 对象中存储的 `flag` 对象在默认构造时是清除 (`false`) 状态。在 `lock()` 函数中调用 `test_and_set` 函数,它是原子的,只有一个线程能成功调用并将 `flag` 的状态原子地更改为设置 (`true`),并返回它先前的值 (`false`)。此时,该线程成功获取了锁,退出循环。
313313

314-
`flag` 对象的状态为设置 (`true`) 时,其线程调用 `test_and_set` 函数会返回 `true`,导致它们继续在循环中自旋,无法退出。直到先前持有锁的线程调用 `unlock()` 函数,将 `flag` 对象的状态原子地更改为清除 (`false`) 状态。此时,等待的线程中会有一个线程成功调用 `test_and_set` 返回 `false`,然后退出循环,成功获取锁。
314+
`flag` 对象的状态为设置 (`true`) 时,其它线程调用 `test_and_set` 函数会返回 `true`,导致它们继续在循环中自旋,无法退出。直到先前持有锁的线程调用 `unlock()` 函数,将 `flag` 对象的状态原子地更改为清除 (`false`) 状态。此时,等待的线程中会有一个线程成功调用 `test_and_set` 返回 `false`,然后退出循环,成功获取锁。
315315

316316
> 值得注意的是,我们只是稍微的讲一下使用 `std::atomic_flag` 实现自旋锁。不过并不推荐各位在实践中使用它,具体可参见 [**Linus Torvalds**](https://en.wikipedia.org/wiki/Linus_Torvalds)[文章](https://www.realworldtech.com/forum/?threadid=189711&curpostid=189723)。其中有一段话说得很直接:
317317
>

0 commit comments

Comments
 (0)