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