## messager 模块说明 此模块中定义了一种消息交互方式,publish负责推送,subscribe负责订阅。其原理是通过subscribe在静态存储区定义了函数,通过publish指定其函数名称,即可调用此静态函数。 此模块中还定义了一种服务的实现方式。add_server_func用于注册服务,get_server_func取得服务,另外还有has_server和remove_server_func可以用于判断服务是否存在和删除服务。 > 消息交互和服务两种方式看起来确有相似之处,但是其含义有明显不同。消息交互目的是推送参数,然后由订阅的函数进行相应的处理,不同的地方,也可以对相同的消息做出不同的处理。而服务由一个模块提供,其实现也只能有一个,在其他模块中也只能是补充参数进行调用。 ### 使用方式 1. 消息交互 在一处或多处使用subscribe订阅消息,并设置对应的处理方式。在另一处使用publish推送消息,此时会自动调用多处subscribe的处理方式。 2. 服务 在一处使用add_server_func注册服务,在另一处使用get_server_func,获取服务并给予适当的参数,获取函数的反馈或为服务中更新一些东西。 > 注:无论哪一种,单独调用一方面都是安全的。只使用subscribe没有publish,则不会触发调用。只有publish则不会做任何处理,也不会有问题。服务也是类似。 ### 服务机制使用示例 设置场景: 模块A中提供生产香飘飘奶茶(赞助商)的服务, 模块B中,需要使用生产奶茶的服务. ``` // 奶茶的定义 class Meco { public: // 提供大中小杯子, 和甜度要求. 生成相应的奶茶 Meco(int _size, float _sugar) : size(_size), sugar(_sugar) {} private: int size; float sugar; }; ``` ``` // 模块A Messager::add_server_func("get_a_meco", [](int size, float sugar) -> Meco { return Meco(size, sugar); }); ``` ``` // 模块B, if (Messager::has_server("get_a_meco")) { auto get_a_meco = get_server_func("get_a_meco"); // 这个if是必须要加的, 上面的has_server是可以不加的. 在多线程中, 存在在其他线程调用remove_server_func函数的可能, 导致这里获得空函数, 直接调用出错. // get_server_func调用是安全的, 如果服务不存在, 只是返回空指针而已, 所以has_server是可以省略的 if (get_a_meco) { auto my_meco = get_a_meco(2, 0.8); // 中杯, 8分甜 // ..... } } ``` ### 消息机制使用示例 设置场景: 在马戏团中的一只海豚, 听驯兽师的指令, 做出规范动作. 模块A模拟驯兽师发出指令, 模块B模拟海豚响应指令. ``` // 驯兽师 // 设定一次 "play_ball" 指令持续ns, 听到"stop"指令或超过ns, 则停止. Messager::publish("play_ball", 10); sleep(7); Messager::publish("stop");l ``` ``` // 海豚 Messager::subcribe("play_ball", [&](int sec) { _is_stop = true; int64_t start = AppUtil::get_current_ms(); while (AppUtil::get_current_ms() - start < sec * 1000 && (!_is_stop)) { play_ball(); // 用时很短, ms级别 } }); Messager::subcribe("stop", [&](){ _is_stop = true; }); ```