C++ blocking message bus message_bus implementation

I. Overview

  • This implementation refers to a general C++ message bus framework , code location: messagebus.h
  • The message bus mainly solves the coupling problem among multiple modules and is blocking.
  • The basic principle of the message bus implementation is as follows: the communicated object publishes a topic to the message bus, which includes a message topic and a message processing function. The message topic marks a specific topic, and the message processing function is used to respond to a certain message type of the topic. . The communication object sends a specific topic and message parameters to the message bus, and the bus will find the corresponding message processing function to process the request according to the message topic and message parameters.
  • The most important thing is that this member object boost::unordered_multimap<string, boost::any> m_map;
    is implemented in other language versions:
  • The implementation of the message bus in lua language: Lua simple message bus implementation, similar to the signal slot of C++ Qt
  • Implementation of message bus in python language: Python simple message bus implementation, similar to C++ Qt's signal slot

Two, implement the code

  • messagebus.h needs to use C++17, the version that does not contain boost, and uses std::any.
#pragma once

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

// 简单的消息分发机制
// ref:https://www.cnblogs.com/qicosmos/archive/2013/04/28/3048919.html
// 《深入应用C++11代码优化与工程级应用》第12章
class MessageBus
{
    
    
public:
    // regist message
    template< class... _Args, class _Func, class = typename std::enable_if<!std::is_member_function_pointer<_Func>::value>::type>
    void attach(std::string key, _Func && func)
    {
    
    
        std::function<void(_Args...)> fn = [&](_Args... args) {
    
     return func(std::forward<_Args>(args)...); };
        m_map.insert(std::make_pair(key, std::move(fn)));
    }

    // non-const member function
    template<class... _Args, class _Class, class... _DeclareArgs, class _Object>
    void attach(std::string key, void(_Class::*func)(_DeclareArgs...), _Object & object)
    {
    
    
        std::function<void(_Args...)> fn = [&, func](_Args... args) {
    
     return (object.*func)(std::forward<_Args>(args)...); };
        m_map.insert(std::make_pair(key, fn));
    }

    // const member function
    template<class... _Args, class _Class, class... _DeclareArgs, class _Object>
    void attach(std::string key, void(_Class::*func)(_DeclareArgs...) const, _Object & object)
    {
    
    
        std::function<void(_Args...)> fn = [&, func](_Args... args) {
    
     return (object.*func)(std::forward<_Args>(args)...); };
        m_map.insert(std::make_pair(key, fn));
    }

    // Broadcast messages, call all the callback functions
    template<typename... _Args>
    void sendMessage(std::string key, _Args... args)
    {
    
    
        auto range = m_map.equal_range(key);
        for (auto it = range.first; it != range.second; it++)
        {
    
    
            std::function<void(_Args...)> func = std::any_cast<std::function<void(_Args...)>>(it->second);
            func(args...);
        }
    }

    // remove message
    template<typename... _Args>
    void remove(std::string key)
    {
    
    
        auto range = m_map.equal_range(key);
        m_map.erase(range.first, range.second);
    }

public:
    MessageBus() = default;
    ~MessageBus() = default;
private:
    MessageBus(const MessageBus&) = delete;
    MessageBus& operator=(const MessageBus&) = delete;

    static std::multimap<std::string, std::any> m_map;
};

static MessageBus g_messagebus; // 全局消息总线
  • messagebus.h , contains boost version
#pragma once

#include <functional>
#include <map>
#include <string>
#include <iostream>

#include <boost/any.hpp>
#include <boost/lexical_cast.hpp>

// 简单的消息分发机制
// ref:https://www.cnblogs.com/qicosmos/archive/2013/04/28/3048919.html
// 《深入应用C++11代码优化与工程级应用》第12章
class MessageBus
{
    
    
public:
    // regist message
    template< class... _Args, class _Func, class = typename std::enable_if<!std::is_member_function_pointer<_Func>::value>::type>
    void attach(std::string key, _Func && func)
    {
    
    
        std::function<void(_Args...)> fn = [&](_Args... args) {
    
     return func(std::forward<_Args>(args)...); };
        m_map.insert(std::make_pair(key, std::move(fn)));
    }

    // non-const member function
    template<class... _Args, class _Class, class... _DeclareArgs, class _Object>
    void attach(std::string key, void(_Class::*func)(_DeclareArgs...), _Object & object)
    {
    
    
        std::function<void(_Args...)> fn = [&, func](_Args... args) {
    
     return (object.*func)(std::forward<_Args>(args)...); };
        m_map.insert(std::make_pair(key, fn));
    }

    // const member function
    template<class... _Args, class _Class, class... _DeclareArgs, class _Object>
    void attach(std::string key, void(_Class::*func)(_DeclareArgs...) const, _Object & object)
    {
    
    
        std::function<void(_Args...)> fn = [&, func](_Args... args) {
    
     return (object.*func)(std::forward<_Args>(args)...); };
        m_map.insert(std::make_pair(key, fn));
    }

    // Broadcast messages, call all the callback functions
    template<typename... _Args>
    void sendMessage(std::string key, _Args... args)
    {
    
    
        auto range = m_map.equal_range(key);
        for (auto it = range.first; it != range.second; it++)
        {
    
    
            std::function<void(_Args...)> func = boost::any_cast<std::function<void(_Args...)>>(it->second);
            func(args...);
        }
    }

    // remove message
    template<typename... _Args>
    void remove(std::string key)
    {
    
    
        auto range = m_map.equal_range(key);
        m_map.erase(range.first, range.second);
    }

public:
    MessageBus() = default;
    ~MessageBus() = default;
private:
    MessageBus(const MessageBus&) = delete;
    MessageBus& operator=(const MessageBus&) = delete;

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

static MessageBus g_messagebus; // 全局消息总线

3. How to use

  • Implement m_map in any cpp file, such as in the main function;
  • Use the global g_messagebus to subscribe to interested messages and callback functions in the required subscription module;
  • Fill in the business logic in the code that needs to publish the message sendMessage.
#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 test(int, const char*) {
    
     
		std::cout<< "hit test" << std::endl; 
		return;
	}
};
int main()
{
    
    
    Test t;
	std::string key = "test";
    // 订阅"test"消息,回调函数为Test::test
    g_messagebus.attach<int, const char*>(key, &Test::test, t); 
    // 向订阅者发送消息,消息参数是 123 和 "abc",回调函数Test::test将会被执行
    g_messagebus.sendMessage<int, const char*>(key, 123, "abc"); 
    // 移除订阅"test"
    g_messagebus.remove<int, const char*>(key); 
    return 0;
}
   

4. Implementation of non-blocking message bus

+ Please refer to my other blog: non-blocking message bus message_bus implemented using C++11

Guess you like

Origin blog.csdn.net/stallion5632/article/details/126096849