2020年5月21日
上一篇怎样说到下图所示的处理数据的流程,我给出了Sensor类的实现。那么这个类是针对线阵相机的数据结构实现的,如果我现在换成3D相机又该怎么操作,我发现只要更换数据结构体就行,其他都可以不用动。再进一步思考,这个模型适用的情形总可以是“一头高频次的出数据,另一头不断地处理数据”。那我完全可以将这一套逻辑封装成一个模板类。
template<typename D>
class proSensor
{
......
}
可以将D换成任何类型的数据。
#pragma once
#include <windows.h>
template<typename D>
class proSensor
{
public:
using DATA = std::shared_ptr<D>;
using OnData = std::function<int(void* _system, void* _context, DATA _data)>;
proSensor(void* _system, OnData callback);
~proSensor();
void PushDataInQueue(DATA data);
private:
void ProcessDataQueue(void* para);
std::mutex m_DataMtx_;
std::queue<DATA> m_QueCamData_;
std::condition_variable m_DataVar_;
bool m_bQueExit_ = false;
std::shared_ptr<SThreadPool> m_Pool_;
std::future<void> m_fuProcessDataQue_;
OnData m_fnData_ = nullptr;
void* m_System_ = nullptr;
void* m_Context_ = nullptr;
};
template<typename D >
proSensor<D>::proSensor(void* _system, OnData callback)
{
m_fuProcessDataQue_ = std::async(std::launch::async, &proSensor<D>::ProcessDataQueue, this, nullptr);
m_fnData_ = callback;
m_Context_ = this;
m_System_ = _system;
}
template<typename D >
proSensor<D>::~proSensor()
{
{
std::unique_lock<std::mutex> locker(m_DataMtx_);
m_bQueExit_ = true;
}
m_DataVar_.notify_one();
m_fuProcessDataQue_.get();
}
template<typename D>
void proSensor<D>::PushDataInQueue(DATA data)
{
//将数据压入到队列中
{
std::unique_lock<std::mutex> lock(m_DataMtx_);
m_QueCamData_.push(data);
}
m_DataVar_.notify_one();//通知另外一个线程进行数据的处理
}
//将队列中的数据弹出,并从回调中获取
template<typename D>
void proSensor<D>::ProcessDataQueue(void* para)
{
DATA tempdata;
std::unique_lock<std::mutex> locker(m_DataMtx_);
while (true)
{
try
{
if (!m_bQueExit_) m_DataVar_.wait(locker);
locker.unlock();
while (true)
{
locker.lock();
if (m_QueCamData_.empty())
{
std::cout << "camera set queue is empty.\n";
break;
}
else
{
tempdata = m_QueCamData_.front();
m_QueCamData_.pop();
}
locker.unlock();
if (m_fnData_)
m_fnData_(m_System_, m_Context_, tempdata);
}
}
catch (const std::exception& e)
{
std::cout << e.what() << "\n";
}
if (m_bQueExit_)
{
break;
}
}
}
下面做了个简单实现,详细看注释。
头文件定义
#include <iostream>
#include "proSensorData.h"
#include "SThreadPool.h"
struct BeforeCameraData
{
int height;
int width;
int datasize;
char* data;
UINT64 timestamps;
};
struct AfterCameraData
{
int height;
int width;
int datasize;
std::unique_ptr<char[]> data;
UINT64 timestamps;
};
class Cameras
{
public:
Cameras();
~Cameras() {}
//相机回调,并在回调中将相机数据压入容器中//
friend int WINAPI s_ManagaGetImageCallBack(void* _context, void* _system, void* _data);
friend int WINAPI s_ProcessLineData(void* _system, void* _context, std::shared_ptr<AfterCameraData> data);
friend void t_SaveImage(void* para, std::shared_ptr<AfterCameraData> data);
private:
std::shared_ptr<SThreadPool> m_ThreadPool_ = nullptr;
std::shared_ptr<proSensor<AfterCameraData>> m_proCamera_;
};
实现
int WINAPI s_ManagaGetImageCallBack(void* _context, void* _system, void* _data)
{
BeforeCameraData* BeData = (BeforeCameraData*)_data;
Cameras* pThis = (Cameras*)_context;
//...将BeforeCameraData转化为AfterCameraData
//为了方便管理将数据地址转化为智能指针
std::shared_ptr<AfterCameraData> afdata;
pThis->m_proCamera_->PushDataInQueue(afdata);
return 0;
}
void t_SaveCameraImage(void* para, std::shared_ptr<AfterCameraData> data)
{
//do what you want
}
int WINAPI s_ProcessLineData(void* _system, void* _context, std::shared_ptr<AfterCameraData> data)
{
Cameras* pThis = (Cameras*)_system;
//多线程的方式处理数据,当然也可以用单线程
pThis->m_ThreadPool_->enqueue(t_SaveCameraImage, pThis, data);
return 0;
}
Cameras::Cameras()
{
//获取系统的"核数",初始化线程池//
unsigned long hardwares = std::thread::hardware_concurrency();
m_ThreadPool_ = std::make_shared<SThreadPool>(hardwares);
//用this指针和回调函数初始化模板类//
m_proCamera_ = std::make_shared<proSensor<AfterCameraData>>(this, s_ProcessLineData);
}
欢迎留言探讨,有疑问也可加我微信进行交流。