基于发布-订阅模型的多线程通信框架

c++实现的一个简易实用的多线程间通信的框架,利用chatGPT实现的😊,已通过测试。需支持c++11标准。实际使用中可以根据需要把数据包装成json格式的字符串再发布

multiThreadComm.h:

#ifndef _MULTITHREADCOMMS_H_
#define _MULTITHREADCOMMS_H_
 
#include <functional>
#include <map>
#include <mutex>
#include <condition_variable>
#include <set>
#include <queue>
#include <string>
#include <atomic>
 
class MTComm {
public:
    using Callback = std::function<void(const std::string&, void* context)>;
 
    MTComm();
    ~MTComm();
 
    void subscribe(const std::string& topic, const std::string& subscriber, Callback callback, void* context);
    void unsubscribe(const std::string& topic, const std::string& subscriber);
    void publish(const std::string& topic, const std::string& message);
 
private:
    void run();
 
private:
    bool running_;
    std::mutex mtxsubs_, mtxmsgs_;
    std::condition_variable cv_;
    std::map<std::string, std::pair<std::set<std::string>, void*>> subscribers_;
    std::queue<std::pair<std::string, std::string>> messages_;
    std::map<std::string, std::pair<Callback, void*>> callbacks_;
};
 
 
#endif // _MULTITHREADCOMMS_H_

multiThreadComm.cpp:

#include "multiThreadComm.h"
#include <thread>
#include <iostream>
 
MTComm::MTComm() : running_(true)
{
    // 启动转发线程
    std::thread t(&MTComm::run, this);
    t.detach();
}
 
MTComm::~MTComm()
{
    // 停止转发线程
    running_ = false;
    cv_.notify_one();
}

// 不要在回调函数中调用subscribe或者unsubscribe,否则会造成死锁
void MTComm::subscribe(const std::string &topic, const std::string &subscriber, Callback callback, void *context)
{
    std::lock_guard<std::mutex> lock_subs(mtxsubs_);
    if (callback)
    {
        auto it = subscribers_.find(topic);
        if (it != subscribers_.end())
        {
            auto &subs = it->second.first;
            if (subs.find(subscriber) == subs.end())
            {
                subs.insert(subscriber);
                callbacks_[subscriber] = std::make_pair(std::move(callback), context);
            }
        }
        else
        {
            std::set<std::string> subs;
            subs.insert(subscriber);
            subscribers_[topic] = std::make_pair(subs, context);
            callbacks_[subscriber] = std::make_pair(std::move(callback), context);
        }
    }
}
 
void MTComm::unsubscribe(const std::string &topic, const std::string &subscriber)
{
    std::lock_guard<std::mutex> lock_subs(mtxsubs_);
    auto it = subscribers_.find(topic);
    if (it != subscribers_.end())
    {
        std::set<std::string> &subs = it->second.first;
        subs.erase(subscriber);
        callbacks_.erase(subscriber);
        if (subs.empty()) // 如果没有订阅者了,从映射表中移除该主题
        {
            subscribers_.erase(it);
        }
    }
}
 
void MTComm::publish(const std::string &topic, const std::string &message)
{
    std::unique_lock<std::mutex> lock_msgs(mtxmsgs_);
    messages_.push({topic, message});
    cv_.notify_one();
}
 
void MTComm::run()
{
    std::unique_lock<std::mutex> lock_msgs(mtxmsgs_);
 
    while (running_)
    {
        // 等待有新消息或者被要求退出
        cv_.wait(lock_msgs, [this]()
                 { return !messages_.empty() || !running_; });
        if (!running_)
        {
            break;
        }
        // 转发消息
        while (!messages_.empty())
        {
            std::lock_guard<std::mutex> lock_subs(mtxsubs_);
            auto message = messages_.front();
            messages_.pop();
            lock_msgs.unlock();
            auto it = subscribers_.find(message.first);
            if (it != subscribers_.end())
            {
                for (const auto &subscriber : it->second.first)
                {
                    auto callbackIt = callbacks_.find(subscriber);
                    if (callbackIt != callbacks_.end())
                    {
                        callbackIt->second.first(message.second, callbackIt->second.second);
                    }
                }
            }
            else
            {
                // 主题不存在
                std::cout << "Warning: Topic not found - " << message.first << std::endl;
            }
            lock_msgs.lock();
        }
    }
}

使用demo,把类的成员函数传入回调的两种方法,当然也可以直接传入全局函数

#include <iostream>
#include <thread>
#include "multiThreadComm.h"
 
class MyClass
{
public:
    void onMessageReceived(const std::string &message, void* context)
    {
        std::cout << "Received message: " << message << std::endl;
		if(context != nullptr)
		{
			int* p_num = reinterpret_cast<int*>(context);
			std::cout << "num: " << *p_num << std::endl;
		}
    }
};
 
MTComm *mmtCom = nullptr;

void thread1()
{
    // 发布消息
    mmtCom->publish("my-topic1", "Hello, subscriber1!");
    mmtCom->publish("my-topic2", "Hello, subscriber2!");
}

int main()
{
    MyClass myObj;
 
	mmtCom = new MTComm;

    /* 订阅主题 */
    // 使用lambda表达式将myObj的成员函数传入回调
    mmtCom->subscribe("my-topic1", "my-subscriber1", [&myObj](const std::string &message, void* context)
                     { myObj.onMessageReceived(message, context); }, nullptr);
 
    // 使用std::bind将myObj的成员函数传入回调
	int *num = new int(10);
    mmtCom->subscribe("my-topic2", "my-subscriber2",
                     std::bind(&MyClass::onMessageReceived, &myObj, std::placeholders::_1, std::placeholders::_2), num);
                     
    std::thread t1(thread1);
                    
    // 等待消息被处理
    std::this_thread::sleep_for(std::chrono::seconds(1));
	
    t1.join();
	delete mmtCom;
	delete num;
 
    return 0;
}

输出:

Received message: Hello, subscriber1!
Received message: Hello, subscriber2!
num: 10

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值