c++实现的一个简洁实用的多线程间通信的框架,利用chatGPT实现的😊,已通过测试。需支持c++11标准。实际使用中可以根据需要把数据包装成json格式的字符串再发布
multiThreadComm.h:
#ifndef _MULTITHREADCOMMS_H_
#define _MULTITHREADCOMMS_H_
#include <functional>
#include <unordered_map>
#include <mutex>
#include <condition_variable>
#include <set>
#include <queue>
#include <string>
#include <atomic>
#include <memory>
class MTComm
{
public:
using Callback = std::function<void(const std::string &, void *context)>;
// 获取单例实例
static MTComm &getInst();
// 禁止拷贝构造和赋值
MTComm(const MTComm &) = delete;
MTComm &operator=(const MTComm &) = delete;
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:
MTComm(); // 构造函数
~MTComm(); // 析构函数
void run(); // 消息处理线程
private:
bool running_; // 运行状态标志
std::mutex mtxsubs_, mtxmsgs_; // 互斥锁
std::condition_variable cv_; // 条件变量
std::unordered_map<std::string, std::pair<std::set<std::string>, void *>> subscribers_; // 订阅者列表
std::queue<std::pair<std::string, std::string>> messages_; // 消息队列
std::unordered_map<std::string, std::pair<Callback, void *>> callbacks_; // 回调函数映射
};
#endif // _MULTITHREADCOMMS_H_
multiThreadComm.cpp:
#include "multiThreadComm.h"
#include <thread>
#include <iostream>
MTComm &MTComm::getInst()
{
static MTComm instance; // 局部静态变量,保证实例唯一性
return instance;
}
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;
}
}
};
void thread1()
{
// 发布消息
MTComm::getInst().publish("my-topic1", "Hello, subscriber1!");
MTComm::getInst().publish("my-topic2", "Hello, subscriber2!");
}
int main()
{
MyClass myObj;
/* 订阅主题 */
// 使用lambda表达式将myObj的成员函数传入回调
MTComm::getInst().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);
MTComm::getInst().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 num;
return 0;
}
输出:
Received message: Hello, subscriber1!
Received message: Hello, subscriber2!
num: 10
文章介绍了一个使用C++11标准实现的简易多线程通信框架,它支持订阅和发布机制,允许线程间通过字符串消息进行通信。框架使用了条件变量、互斥锁等同步原语保证线程安全,并提供了通过回调函数处理接收到的消息的功能。示例代码展示了如何订阅主题并使用成员函数作为回调。
5964

被折叠的 条评论
为什么被折叠?



