异步处理 、事件驱动编程、和 策略模式
一、异步处理(Asynchronous Processing)
定义:
异步处理是一种编程模型,允许任务在等待耗时操作(如 I/O、网络请求)完成的同时,不阻塞其他任务的执行。
类比场景:
排队点奶茶 vs 自助取号叫号系统
- 同步处理: 你在柜台排队点奶茶,等前面的人点完才轮到你。
- 异步处理: 你在门口的机器上取个号,然后在旁边玩手机,等叫到你再上前点单。
你不必等前面所有人点完才能做别的事(=不会阻塞主线程)。
代码示例(C++ 伪代码):
cpp
#include <future>
#include <iostream>
int longTask() {
std::this_thread::sleep_for(std::chrono::seconds(3));
return 42;
}
int main() {
std::future<int> result = std::async(std::launch::async, longTask);
std::cout << "任务开始,我先去做别的事情...\n";
// 等待 longTask 完成
int value = result.get();
std::cout << "任务结果:" << value << std::endl;
return 0;
}
二、事件驱动编程(Event-Driven Programming)
定义:
事件驱动是一种编程范式,程序的流程由事件(Event)触发来控制。每当某个事件发生,就调用对应的"事件处理器"。
类比场景:
门铃系统
- 门口安装了一个门铃(event)。
- 有人按门铃(事件发生),系统立刻响铃或通知你(事件处理器)。
- 没人按门铃时,你可以自由做别的事。
你不需要时刻去检测门口是否有人,而是等事件触发你再响应。
代码示例(JavaScript 常见):
javascript
document.getElementById("myButton").addEventListener("click", function() {
alert("按钮被点击了!");
});
你设置一个事件监听器(Event Listener),当"点击事件"发生时执行某段代码。
C++ 中可以通过回调函数、观察者模式等方式实现类似的事件驱动效果。
三、策略模式(Strategy Pattern)
定义:
策略模式是一种行为设计模式,定义一系列算法,把它们封装起来,并且使它们可以相互替换。客户端不关心具体策略细节,只关注调用统一接口。
类比场景:
导航路线选择
- 你要开车去目的地,可以选择:最快路线 、最短路线 、避开收费。
- 不同的策略(开车方式)可以随时切换,但你都只管告诉系统"带我去"。
系统内部选择使用哪个策略,用户无感。
C++ 示例代码:
cpp
// 策略接口
class TravelStrategy {
public:
virtual void travel() = 0;
};
// 具体策略1
class CarStrategy : public TravelStrategy {
public:
void travel() override {
std::cout << "开车去旅行\n";
}
};
// 具体策略2
class TrainStrategy : public TravelStrategy {
public:
void travel() override {
std::cout << "坐火车去旅行\n";
}
};
// 上下文(使用策略的环境)
class TravelContext {
private:
TravelStrategy* strategy;
public:
void setStrategy(TravelStrategy* s) {
strategy = s;
}
void go() {
strategy->travel();
}
};
// 使用
int main() {
TravelContext ctx;
CarStrategy car;
TrainStrategy train;
ctx.setStrategy(&car);
ctx.go(); // 输出:开车去旅行
ctx.setStrategy(&train);
ctx.go(); // 输出:坐火车去旅行
return 0;
}
总结对比表:
名称 | 核心思想 | 类比场景 | 应用场景 |
---|---|---|---|
异步处理 | 不阻塞当前线程,等待操作完成 | 奶茶取号系统 | 网络通信、文件IO |
事件驱动编程 | 响应事件触发,执行特定操作 | 按门铃触发动作 | UI开发、网络服务器 |
策略模式 | 行为封装,可随时替换使用方式 | 不同路线导航选择 | 可切换的算法或行为(如排序) |
异步处理、事件驱动编程和策略模式 在嵌入式 C++ 中的运用
一、异步处理在嵌入式 C++ 中的运用
定义与场景
嵌入式系统中常需要处理耗时的操作,例如:
- 串口、以太网通信
- 传感器数据采集
- SD 卡或 NAND Flash 读写
- OTA 升级等文件传输
这些操作如果同步执行,会阻塞主线程,影响系统的实时性与响应能力。
运用方式
- 使用 RTOS 中的任务调度或消息队列
- 使用中断回调函数 + 状态机机制
- 引入异步 I/O 框架(如 Boost.Asio)统一管理异步操作
示例:异步读取串口数据
cpp
void uart_read_callback(uint8_t* data, size_t len) {
// 处理接收到的数据
}
void poll_uart() {
if (uart_data_available()) {
uint8_t buffer[64];
size_t len = uart_read(buffer, sizeof(buffer));
uart_read_callback(buffer, len);
}
}
二、事件驱动编程在嵌入式 C++ 中的运用
定义与场景
事件驱动是一种通过事件(如中断、输入)来控制流程的编程方式。常见事件包括:
- 按键按下
- 定时器中断
- 外设数据到达(UART、SPI)
- 网络事件(连接、断开)
运用方式
- 利用中断服务程序设置事件标志或往事件队列投递消息
- 在主循环中轮询事件队列并执行对应处理器
- 使用状态机结合事件系统
示例:事件驱动模型伪代码
cpp
enum EventType {
EVENT_BUTTON_PRESS,
EVENT_UART_RX,
...
};
struct Event {
EventType type;
void* data;
};
std::queue<Event> event_queue;
void isr_button_press() {
event_queue.push({EVENT_BUTTON_PRESS, nullptr});
}
void event_loop() {
while (true) {
if (!event_queue.empty()) {
Event evt = event_queue.front();
event_queue.pop();
switch (evt.type) {
case EVENT_BUTTON_PRESS:
handle_button();
break;
case EVENT_UART_RX:
handle_uart(evt.data);
break;
}
}
}
}
三、策略模式在嵌入式 C++ 中的运用
定义与场景
策略模式用于在运行时动态选择行为实现,是一种面向对象的解耦方式。嵌入式中可用于以下场景:
- 选择不同通信方式(如 SPI、UART、I2C)
- 切换加密算法或数据编码方式
- 控制日志输出行为(输出到串口或文件)
运用方式
- 抽象接口定义行为
- 多个具体类分别实现该行为
- 通过 setStrategy() 等接口注入行为
示例:发送策略(UART / SPI)
cpp
class SendStrategy {
public:
virtual void send(const uint8_t* data, size_t len) = 0;
};
class UartSend : public SendStrategy {
public:
void send(const uint8_t* data, size_t len) override {
uart_send(data, len);
}
};
class SpiSend : public SendStrategy {
public:
void send(const uint8_t* data, size_t len) override {
spi_send(data, len);
}
};
class Device {
SendStrategy* strategy;
public:
void setStrategy(SendStrategy* s) { strategy = s; }
void transmit(const uint8_t* data, size_t len) {
strategy->send(data, len);
}
};
四、Boost.Asio 在嵌入式 C++ 中的详细说明
简介
Boost.Asio 是一个跨平台的异步 I/O 库,提供统一接口处理异步串口、定时器、网络通信等。其主要优点是抽象统一、无需依赖多线程即可实现非阻塞操作。
核心概念
组件 | 描述 |
---|---|
io_context |
核心事件循环调度器 |
serial_port |
串口抽象对象,封装串口操作 |
steady_timer |
定时器,用于定时异步回调 |
async_* 函数 |
执行异步任务,如 async_read, async_write |
handler |
异步完成后的回调 |
strand |
保证回调序列化执行 |
示例:串口异步接收
cpp
#include <boost/asio.hpp>
#include <iostream>
using namespace boost;
asio::io_context io;
asio::serial_port serial(io, "/dev/ttyUSB0");
char read_buf[256];
void read_handler(const system::error_code& ec, std::size_t bytes_transferred) {
if (!ec) {
std::cout << "Received: " << std::string(read_buf, bytes_transferred) << std::endl;
serial.async_read_some(asio::buffer(read_buf), read_handler); // 再次接收
}
}
int main() {
serial.set_option(asio::serial_port_base::baud_rate(9600));
serial.async_read_some(asio::buffer(read_buf), read_handler);
io.run(); // 启动事件循环
return 0;
}
在嵌入式环境中使用建议
项目 | 建议说明 |
---|---|
资源优化 | 关闭异常处理(-fno-exceptions ) |
平台适配 | 可交叉编译至 ARM Cortex-M / Linux |
可裁剪性 | 移除 TCP/UDP 支持,仅保留串口和定时器模块 |
替代方案 | libuv、libevent、或裸写异步驱动 |
总结
项目/模式 | 嵌入式中作用 | 示例场景 |
---|---|---|
异步处理 | 非阻塞等待,提高系统响应 | 串口、文件IO、OTA |
事件驱动编程 | 精准控制流程、节省资源 | 中断处理、外设事件 |
策略模式 | 支持行为切换、增加灵活性 | 通信方式切换、算法选择 |
Boost.Asio | 跨平台高效异步库,简化异步操作 | 异步串口、定时器、轻量网络服务 |
