【C++】自定义一个通用的数据收发类

项目场景:

刚入职公司不久,主要负责一个后端程序的开发。最近开发新项目,需要将设备中收到的数据通过串口发送给后端程序,后端处理完后发送给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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fairyseason73

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值