C++的阻塞式消息总线message_bus实现

一、概述

本实现参考自一个通用的C++ 消息总线框架,代码位置:messagebus.h

该消息总线主要解决多个模块间的耦合问题,是阻塞式的。其基本原理如下:

  • 通信对象向消息总线发布一个主题,包含消息主题和消息处理函数。
  • 消息主题标示特定主题,消息处理函数用来响应该主题的某种消息类型。
  • 通信对象向消息总线发送特定主题和消息参数,总线根据消息主题和消息参数找到对应的消息处理函数来处理请求。

关键成员对象:static std::multimap<std::string, std::any> m_map;

其它语言版本的实现:

二、实现代码

不含Boost的版本(使用C++17标准库)

#pragma once

#include <functional>
#include <map>
#include <string>
#include <any>

// 简单的消息分发机制
class MessageBus {
 public:
  // 注册非成员函数或静态成员函数
  template <class... Args, class Func,
            class = std::enable_if_t<!std::is_member_function_pointer_v<Func>>>
  void Attach(const std::string& key, Func&& func) {
    std::function<void(Args...)> fn = std::forward<Func>(func);
    m_map_.emplace(key, std::move(fn));
  }

  // 注册非常量成员函数
  template <class... Args, class Class, class... DeclaredArgs, class Object>
  void Attach(const std::string& key, void (Class::*func)(DeclaredArgs...), Object& object) {
    std::function<void(Args...)> fn = [&object, func](Args... args) {
      (object.*func)(std::forward<Args>(args)...);
    };
    m_map_.emplace(key, std::move(fn));
  }

  // 注册常量成员函数
  template <class... Args, class Class, class... DeclaredArgs, class Object>
  void Attach(const std::string& key, void (Class::*func)(DeclaredArgs...) const, Object& object) {
    std::function<void(Args...)> fn = [&object, func](Args... args) {
      (object.*func)(std::forward<Args>(args)...);
    };
    m_map_.emplace(key, std::move(fn));
  }

  // 广播消息,调用所有回调函数
  template <typename... Args>
  void SendMessage(const std::string& key, Args... args) {
    auto range = m_map_.equal_range(key);
    for (auto it = range.first; it != range.second; ++it) {
      std::any_cast<std::function<void(Args...)>>(it->second)(std::forward<Args>(args)...);
    }
  }

  // 移除指定key的所有回调函数
  void Remove(const std::string& key) {
    m_map_.erase(key);
  }

 private:
  static std::multimap<std::string, std::any> m_map_;
};

std::multimap<std::string, std::any> MessageBus::m_map_;
static MessageBus g_messagebus;  // 全局消息总线

含有Boost的版本

#pragma once

#include <functional>
#include <map>
#include <string>
#include <boost/any.hpp>

// 简单的消息分发机制
class MessageBus {
 public:
  // 注册非成员函数或静态成员函数
  template <class... Args, class Func,
            class = std::enable_if_t<!std::is_member_function_pointer_v<Func>>>
  void Attach(const std::string& key, Func&& func) {
    std::function<void(Args...)> fn = std::forward<Func>(func);
    m_map_.emplace(key, std::move(fn));
  }

  // 注册非常量成员函数
  template <class... Args, class Class, class... DeclaredArgs, class Object>
  void Attach(const std::string& key, void (Class::*func)(DeclaredArgs...), Object& object) {
    std::function<void(Args...)> fn = [&object, func](Args... args) {
      (object.*func)(std::forward<Args>(args)...);
    };
    m_map_.emplace(key, std::move(fn));
  }

  // 注册常量成员函数
  template <class... Args, class Class, class... DeclaredArgs, class Object>
  void Attach(const std::string& key, void (Class::*func)(DeclaredArgs...) const, Object& object) {
    std::function<void(Args...)> fn = [&object, func](Args... args) {
      (object.*func)(std::forward<Args>(args)...);
    };
    m_map_.emplace(key, std::move(fn));
  }

  // 广播消息,调用所有回调函数
  template <typename... Args>
  void SendMessage(const std::string& key, Args... args) {
    auto range = m_map_.equal_range(key);
    for (auto it = range.first; it != range.second; ++it) {
      boost::any_cast<std::function<void(Args...)>>(it->second)(std::forward<Args>(args)...);
    }
  }

  // 移除指定key的所有回调函数
  void Remove(const std::string& key) {
    m_map_.erase(key);
  }

 private:
  static std::multimap<std::string, boost::any> m_map_;
};

std::multimap<std::string, boost::any> MessageBus::m_map_;
static MessageBus g_messagebus;  // 全局消息总线

三、使用方法

在任意一个cpp文件中实现m_map,例如在main函数中:

#include "messagebus.h"
#include <iostream>

std::multimap<std::string, std::any> MessageBus::m_map_;
// 使用boost时:std::multimap<std::string, boost::any> MessageBus::m_map_;

class Test {
 public:
  void TestFunc(int, const char*) {
    std::cout << "hit test" << std::endl;
  }
};

int main() {
  Test t;
  std::string key = "test";

  // 订阅"test"消息,回调函数为Test::TestFunc
  g_messagebus.Attach<int, const char*>(key, &Test::TestFunc, t);
  
  // 向订阅者发送消息,消息参数是123和"abc",回调函数Test::TestFunc将会被执行
  g_messagebus.SendMessage<int, const char*>(key, 123, "abc");
  
  // 移除订阅"test"
  g_messagebus.Remove(key);

  return 0;
}

四、非阻塞消息总线的实现

请参考我的另一篇博客: 使用C++11实现的非阻塞消息总线message_bus

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘色的喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值