待分类·

嵌入式事件回调机制典型案例剖析

Hugh

Hugh

91 0
void OnNetworkError(std::function<void(const std::string& message)> callback);
void Protocol::OnNetworkError(std::function<void(const std::string& message)> callback) 
{ 
on_network_error_ = callback;
 }
protocol_->OnNetworkError(
[this](const std::string &message) 
{
 last_error_message_ = message;
 xEventGroupSetBits(event_group_, MAIN_EVENT_ERROR);
 });
on_network_error_(message);

这四组代码是 “C++ 回调机制从‘声明 → 定义 → 注册 → 触发’的完整链路” ​,每一步都环环相扣,共同实现 “网络错误事件的响应逻辑”。我们可以按 “时间顺序 + 功能分工” 拆解它们的逻辑关系,本质是 “先约定接口 → 实现接口 → 绑定处理逻辑 → 触发处理逻辑” 的过程。

一、四组代码的功能定位先明确

首先用表格清晰区分四组代码的角色:

代码片段功能角色核心作用所在位置
1.void OnNetworkError(std::function callback);接口声明约定 “注册网络错误回调” 的函数格式(返回值、参数类型),告诉上层 “可以这样调用我”Protocol.h(头文件,类的公共接口)
2. void Protocol::OnNetworkError(std::function callback) { on_network_error_ = callback; }接口定义实现 “注册回调” 的逻辑:把上层传入的处理逻辑保存到成员变量,供后续触发Protocol.cc(源文件,类的成员函数实现)
3. protocol_->OnNetworkError([this](const std::string &message) { last_error_message_ = message; xEventGroupSetBits(event_group_, MAIN_EVENT_ERROR); });回调注册上层业务(如 Application)调用接口,把 “网络错误该怎么处理” 的具体逻辑(Lambda)传给 Protocol上层代码(如 Application.cc,初始化协议时)
4. on_network_error_(message);回调触发底层协议(如 MqttProtocol/WebsocketProtocol)检测到网络错误时,调用保存的处理逻辑,执行上层绑定的代码底层协议类(如 MqttProtocol.cc/WebsocketProtocol.cc,错误检测点)

二、逻辑关系:从 “约定” 到 “执行” 的完整流程

这四组代码的逻辑关系,就像 “搭建一个快递代收系统”,我们用生活化的例子类比,再对应到代码:

1. 第一步:约定 “代收规则”(接口声明,代码 1)

你(Protocol 类)是小区代收点,需要告诉业主(上层代码)“你可以怎样把快递交给我代收”—— 这就是 接口声明 的作用。

  • 代码 1 void OnNetworkError(std::function<...> callback); 约定:
    • 业主(上层)要交给你的 “东西”(参数 callback),必须是 “能处理‘快递信息(message)’的逻辑”(std::function 规定的签名:接收 string 类型错误信息,无返回值);
    • 你(Protocol)提供的 “代收服务” 叫 OnNetworkError(函数名),且不收取额外费用(返回值 void)。

这一步的核心是 ​**“定规矩”**​:让上层知道 “该传什么样的处理逻辑”,避免传错格式(比如传一个需要返回值的函数)。

2. 第二步:准备 “代收货架”(接口定义,代码 2)

你(Protocol 类)按约定好的规则,准备一个 “货架”(成员变量 on_network_error_),用来存放业主交给你的 “快递处理逻辑”—— 这就是 接口定义 的作用。

  • 代码 2 的逻辑:
    • on_network_error_Protocol 类的私有成员变量(类型和代码 1 的参数一致:std::function<void(const std::string&)>),相当于 “专门放快递处理逻辑的货架”;
    • 当业主把 “处理逻辑(callback)” 交给你时,你把它放到这个 “货架” 上(on_network_error_ = callback),暂时保存起来,等后续有快递(网络错误)时用。

这一步的核心是 ​**“存逻辑”**​:把上层的处理逻辑 “暂存” 到底层,建立 “上层逻辑” 和 “底层触发” 的桥梁。

3. 第三步:业主 “提交处理需求”(回调注册,代码 3)

业主(上层代码,如 Application)知道了代收规则,也知道你有货架,于是把 “收到快递后该怎么处理” 的具体需求(比如 “快递到了给我发消息 + 放门口”)交给你 —— 这就是 回调注册 的作用。

  • 代码 3 的逻辑:
    • protocol_->OnNetworkError(...):业主(上层)调用你提供的 “代收服务”(OnNetworkError 接口);
    • 传入的 Lambda 表达式 [this](const std::string &message) { ... }:就是业主的具体需求 ——“如果有网络错误(快递到了),先把错误信息存起来(last_error_message_ = message),再触发全局错误事件(xEventGroupSetBits(...),相当于‘给我发消息’)”;
    • 调用后,这个 Lambda 会被代码 2 的逻辑保存到 on_network_error_ 这个 “货架” 上。

这一步的核心是 ​**“绑逻辑”**​:把上层的 “具体处理方式” 和底层的 “接口” 绑定,完成 “上层告诉底层该做什么” 的过程。

4. 第四步:快递到了,按需求处理(回调触发,代码 4)

某天快递员(底层协议,如 MqttProtocol)送来了快递(检测到网络错误,比如 “连接超时”),你(Protocol)从货架上拿出业主之前存的 “处理需求”,按需求执行 —— 这就是 回调触发 的作用。

  • 代码 4 on_network_error_(message); 的逻辑:
    • message 是快递员带来的 “快递信息”(具体的网络错误描述,如 "MQTT server connection timed out");
    • 你(Protocol)检查 “货架”(on_network_error_)是否有业主存的需求(不为空),然后调用这个需求(on_network_error_(message)),把 “快递信息”(message)传给它;
    • 最终执行的就是代码 3 中绑定的 Lambda 逻辑:保存错误信息 + 触发全局错误事件。

这一步的核心是 ​**“执行逻辑”**​:底层检测到事件后,调用上层之前绑定的处理逻辑,完成 “底层触发上层逻辑” 的闭环。

三、总结:四组代码的依赖关系

它们的逻辑依赖是 ​**“线性顺序”**​,缺一不可:

  1. 没有代码 1(接口声明):上层不知道该传什么样的处理逻辑,底层也无法约定接口格式,会出现编译错误;
  2. 没有代码 2(接口定义):上层传的处理逻辑无处可存,“货架” 不存在,注册操作会失效;
  3. 没有代码 3(回调注册):“货架” 是空的,底层即使检测到错误,也没有处理逻辑可执行;
  4. 没有代码 4(回调触发):上层的处理逻辑永远不会被调用,“绑了逻辑却不用”,回调机制失去意义。

简单说:​代码 1 定规则 → 代码 2 搭架子 → 代码 3 填内容 → 代码 4 用内容​,共同构成了 “上层定义逻辑、底层触发执行” 的回调机制,实现了 “网络错误处理” 的解耦(底层只负责检测错误,上层只负责处理错误)。

相关文章

优先推荐同专题、同标签和同作者内容,补足热门文章。

评论 0

登录 后参与评论

评论

成为第一个评论的人