项目场景:
刚入职公司不久,主要负责一个后端程序的开发。最近开发新项目,需要将设备中收到的数据通过串口发送给后端程序,后端处理完后发送给web网页。看了一下公司类似的几个项目,发现这一块都有做了,只不过每个项目需要的数据都不太一样,逻辑都是一样的,遂感觉做了很多无效开发,思来想去就设计了这么一个通用的类,可以对任意数据进行收发。
需求分析:
这个类的主要有以下几个特点
1.通过一个线程接收处理数据、一个线程发送数据
2.因为处理的数据是任意的,因此数据处理的方法不能具体化,那就只能通过回调函数外部设置+模板来实现这个类
3.接收处理回调函数和发送处理回调函数参数列表和返回值都是任意的
这个类主要成员如下
class CDataProcessor {
private:
std::atomic m_running; //
std::atomic m_started;
std::thread m_captureThread; //捕获、接收线程
std::thread m_processThread; //发送线程
std::queuestd::any m_dataQueue; //存放数据队列
std::mutex m_mutex;
std::condition_variable m_dataCV; //数据处理完成后通知发送线程
std::functionstd::any() m_getDataFunc; //捕获、接收回调函数
std::functionstd::any(std::any) m_dataCallback; //发送、通知外部回调函数
}
主要方法有一下几个:
CDataProcessor();
~CDataProcessor();
void start() ;
void stop();
void waitForStop();
void setGetDataFunc
void setDataCallback
void captureThreadFunc()
void sendThreadFunc()
具体实现如下:
CDataProcessor() : m_running(false), m_started(false) {}
~CDataProcessor() {
this->waitForStop();
}
void start() {
bool expected = false;
if (m_started.compare_exchange_strong(expected, true)) {
m_running = true;
m_captureThread = std::thread(&CDataProcessor::captureThreadFunc, this);
m_processThread = std::thread(&CDataProcessor::sendThreadFunc, this);
}
else if (!m_running) {
m_running = true;
m_dataCV.notify_all();
}
}
void stop() {
std::lock_guard<std::mutex> lock(m_mutex);
m_running = false;
m_dataCV.notify_all();
}
void waitForStop() {
stop();
std::unique_lock<std::mutex> lock(m_mutex);
m_dataCV.wait(lock, [this]() { return m_dataQueue.empty(); });
if (m_captureThread.joinable()) {
m_captureThread.join();
}
if (m_processThread.joinable()) {
m_processThread.join();
}
}
// m_getDataFunc 现在是一个可变参数的模板函数
template<typename Func, typename... Args>
void setGetDataFunc(Func&& func, Args&&... args) {
m_getDataFunc = [=]() -> std::any {
return std::apply(func, std::make_tuple(args...));
};
}
// 设置数据回调的函数和参数
// 设置数据回调的函数和参数
template<typename Func, typename... Args>
void setDataCallback(Func&& func, Args&&... args) {
m_dataCallback = [=](std::any data) -> std::any {
using ReturnType = decltype(func(std::declval<Args>()..., std::declval<std::any>()));
if constexpr (std::is_void_v<ReturnType>) {
std::apply(func, std::tuple_cat(std::make_tuple(args...), std::make_tuple(data)));
return std::any{};
}
else {
return std::apply(func, std::tuple_cat(std::make_tuple(args...), std::make_tuple(data)));
}
};
}
void captureThreadFunc() {
while (m_running) {
try {
std::any captureData = m_getDataFunc();
{
std::lock_guard<std::mutex> lock(m_mutex);
m_dataQueue.push(std::move(captureData));
}
m_dataCV.notify_one();
}
catch (const std::exception& e) {
std::cerr << "Exception in captureThreadFunc: " << e.what() << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
void sendThreadFunc() {
while (true) {
std::unique_lock<std::mutex> lock(m_mutex);
m_dataCV.wait(lock, [this]() { return !m_dataQueue.empty() || !m_running; });
if (m_dataQueue.empty() && !m_running) {
break;
}
if (!m_dataQueue.empty()) {
std::any data = std::move(m_dataQueue.front());
m_dataQueue.pop();
lock.unlock();
try {
std::any result = m_dataCallback(data);
std::cout << "sendThreadFunc successed, " << result.type().name() << std::endl;
}
catch (const std::exception& e) {
std::cerr << "Exception in sendThreadFunc: " << e.what() << std::endl;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
## 测试代码如下:
///
/// 测试代码
///
/*
#include <iostream>
#include <random>
struct INFO {
int a = 100;
int b = 200;
};
//获取数据来源函数
int getRandomNumber()
{
// 随机数生成器
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(1, 100);
int randomData = dis(gen);
std::cout << "Random number is: " << randomData << std::endl;
return randomData;
}
std::string sendRadnomData(std::any data) {
try {
int ndata = std::any_cast<int>(data);
std::cout << "sendRadnomData received INFO: a = " << ndata << std::endl;
return "Callback processed INFO data";
}
catch (const std::bad_any_cast& e) {
std::cerr << "Error: " << e.what() << std::endl;
return "Callback failed";
}
}
INFO getinfo(std::string str)
{
std::cout << "get info from " << str << std::endl;
INFO info;
info.a = getRandomNumber(); //获取随机数
info.b = getRandomNumber(); //获取随机数
return info;
}
int main(int argc, char* argv[])
CDataProcessor processor;
processor.setGetDataFunc(getRandomNumber);
processor.setDataCallback(sendRadnomData);
processor.start();
std::this_thread::sleep_for(std::chrono::seconds(5));
processor.waitForStop();
return 0;
}