Skip to content

Commit 8b9dbdc

Browse files
update chapter10 5,6
1 parent 25bb58b commit 8b9dbdc

15 files changed

Lines changed: 6268 additions & 2 deletions
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
// ISR 基础示例 - 演示中断与主线程的数据竞争问题
2+
// 本示例模拟 ISR 执行环境,展示常见的陷阱
3+
4+
#include <cstdint>
5+
#include <cstdio>
6+
#include <thread>
7+
#include <atomic>
8+
#include <vector>
9+
10+
// 模拟硬件寄存器
11+
namespace hal {
12+
// 模拟 UART 数据寄存器(volatile 确保每次都访问硬件)
13+
volatile uint32_t UART_DR = 0;
14+
volatile uint32_t UART_SR = 0;
15+
16+
constexpr uint32_t UART_SR_RXNE = 0x0020; // 接收数据非空
17+
18+
// 模拟中断使能
19+
inline void enable_uart_irq() { /* 实际硬件操作 */ }
20+
}
21+
22+
// ============================================================================
23+
// 反面教材:有数据竞争的代码
24+
// ============================================================================
25+
26+
namespace bad_example {
27+
// ❌ 问题:非原子的共享变量
28+
int shared_counter = 0;
29+
uint8_t received_byte = 0;
30+
bool data_ready = false;
31+
32+
// 模拟 UART 接收中断(ISR)
33+
void uart_rx_isr() {
34+
// 检查接收标志
35+
if (hal::UART_SR & hal::UART_SR_RXNE) {
36+
received_byte = static_cast<uint8_t>(hal::UART_DR);
37+
shared_counter++; // ❌ 数据竞争!
38+
data_ready = true; // ❌ 数据竞争!
39+
}
40+
}
41+
42+
// 主循环
43+
void main_loop() {
44+
if (data_ready) { // ❌ 数据竞争!
45+
printf("Received: 0x%02X, count: %d\n", received_byte, shared_counter);
46+
data_ready = false;
47+
}
48+
}
49+
}
50+
51+
// ============================================================================
52+
// 正确做法:使用原子操作
53+
// ============================================================================
54+
55+
class ISRUARTDriver {
56+
public:
57+
// 编译期检查:确保原子操作是无锁的
58+
static_assert(std::atomic<int>::is_always_lock_free,
59+
"atomic<int> must be lock-free for ISR use!");
60+
61+
ISRUARTDriver() noexcept
62+
: shared_counter(0)
63+
, received_byte(0)
64+
, data_ready(false)
65+
{}
66+
67+
// 模拟 UART 接收中断(ISR)
68+
void uart_rx_isr() noexcept {
69+
if (hal::UART_SR & hal::UART_SR_RXNE) {
70+
received_byte.store(static_cast<uint8_t>(hal::UART_DR),
71+
std::memory_order_relaxed);
72+
shared_counter.fetch_add(1, std::memory_order_relaxed);
73+
// release 确保之前的写入都完成
74+
data_ready.store(true, std::memory_order_release);
75+
}
76+
}
77+
78+
// 主循环
79+
bool main_loop() {
80+
// acquire 确保能看到 ISR 中的所有写入
81+
if (data_ready.load(std::memory_order_acquire)) {
82+
uint8_t data = received_byte.load(std::memory_order_relaxed);
83+
int count = shared_counter.load(std::memory_order_relaxed);
84+
printf("Received: 0x%02X, count: %d\n", data, count);
85+
data_ready.store(false, std::memory_order_release);
86+
return true;
87+
}
88+
return false;
89+
}
90+
91+
private:
92+
std::atomic<int> shared_counter;
93+
std::atomic<uint8_t> received_byte;
94+
std::atomic<bool> data_ready;
95+
};
96+
97+
namespace good_example {
98+
// ✅ 使用原子变量的示例(参考上面的类实现)
99+
}
100+
101+
// ============================================================================
102+
// ISR 禁区演示
103+
// ============================================================================
104+
105+
namespace isr_restriction_demo {
106+
std::atomic<bool> error_flag{false};
107+
108+
// ❌ 错误示例:在 ISR 中使用互斥锁
109+
// class BadISR {
110+
// std::mutex mtx;
111+
// void isr() {
112+
// std::lock_guard<std::mutex> lock(mtx); // ❌ 可能死锁!
113+
// }
114+
// };
115+
116+
// ❌ 错误示例:在 ISR 中分配内存
117+
// void bad_isr() {
118+
// int* p = new int; // ❌ 可能阻塞,可能抛异常
119+
// delete p;
120+
// }
121+
122+
// ❌ 错误示例:在 ISR 中进行长时间操作
123+
// void bad_isr() {
124+
// for (volatile int i = 0; i < 1000000; ++i) { // ❌ 阻塞其他中断
125+
// // 浪费 CPU 时间
126+
// }
127+
// }
128+
129+
// ✅ 正确示例:ISR 只做最少的工作
130+
class GoodISR {
131+
std::atomic<bool> data_ready{false};
132+
uint8_t buffer;
133+
134+
public:
135+
void isr() noexcept {
136+
// 只读取数据并设置标志
137+
buffer = static_cast<uint8_t>(hal::UART_DR);
138+
data_ready.store(true, std::memory_order_release);
139+
}
140+
141+
bool get_data(uint8_t& data) noexcept {
142+
if (data_ready.load(std::memory_order_acquire)) {
143+
data = buffer;
144+
data_ready.store(false, std::memory_order_release);
145+
return true;
146+
}
147+
return false;
148+
}
149+
};
150+
}
151+
152+
// ============================================================================
153+
// 主函数:模拟中断环境
154+
// ============================================================================
155+
156+
int main() {
157+
printf("=== ISR 基础示例 ===\n\n");
158+
159+
// 演示正确做法
160+
printf("正确示例:使用原子操作\n");
161+
printf("------------------------------\n");
162+
163+
ISRUARTDriver isr_system;
164+
165+
// 模拟 10 次中断
166+
for (int i = 0; i < 10; ++i) {
167+
// 模拟硬件接收到数据
168+
hal::UART_SR = hal::UART_SR_RXNE;
169+
hal::UART_DR = 0x40 + i;
170+
171+
// 模拟中断触发
172+
isr_system.uart_rx_isr();
173+
174+
// 清除硬件状态
175+
hal::UART_SR = 0;
176+
}
177+
178+
// 主循环处理数据
179+
int processed = 0;
180+
while (processed < 10) {
181+
if (isr_system.main_loop()) {
182+
processed++;
183+
}
184+
}
185+
186+
printf("\n=== ISR 设计原则 ===\n");
187+
printf("1. ISR 中不能使用互斥锁(可能死锁)\n");
188+
printf("2. ISR 中不能分配内存(可能阻塞/抛异常)\n");
189+
printf("3. ISR 执行时间要短(影响响应性)\n");
190+
printf("4. 访问共享数据必须使用原子操作\n");
191+
printf("5. 用 release/acquire 内存序确保可见性\n");
192+
193+
return 0;
194+
}
195+
196+
// 编译命令:
197+
// g++ -std=c++17 -Wall -Wextra -pthread 01_isr_basics.cpp -o 01_isr_basics

0 commit comments

Comments
 (0)