处理大量数据的一种方法(C++)

处理场景:三台线阵相机或者多台其他传感器与工控机连着,通过调用相机的SDK控制相机,例如同时开关,同时从相机中获取数据。然后采集软件接收到相机数据后,将数据保存到硬盘。

应用场景

处理的问题:如果三台相机发送数据频率很快,并且数据量很大的话,如何快速将数据写入到硬盘里或者对数据的其他处理,从而保证内存不增长?

解决方案简述:每收到一坨相机的数据,就将其从尾部压入队列;同时有另外一个线程在等着处理这个队列,只要这个队列有数据,就从头部弹出一个数据,然后对这个数据进行相应的处理。这里存在一个问题:如果相机频率太快,也就是说队列会涨得非常快,涨数据的速度大于处理数据的速度,内存就会上涨,直至崩溃。处理数据,例如将相机数据保存到硬盘,如果硬盘写数据的速度很慢,就会出现内存涨爆的情况,这个时候可以考虑用多线程进行处理,从队列弹出一个数据后,马上被一个线程接上,这样可以显著提升CPU的利用率,加快数据处理速度。

队列缓存

简要代码如下:

需特别注意代码中的注释。

//头文件代码
#include <iostream>
#include <windows.h>
#include <queue>
#include <mutex>
#include <future>
#include "SThreadPool.h"
struct CameraData
{
    int height;
    int width;
    int datasize;
    std::unique_ptr<char[]> data;
    UINT64 timestamps;
};

class Sensor
{
public:
    Sensor();
    ~Sensor();
    //**获取相机数据的回调,并在回调中将相机数据压入容器中**//
    friend int WINAPI s_ManagaGetImageCallBack(void* _context, void* _system, void* _data);

    //从队列头部弹出数据并进行处理//
    void t_ProcessDataQueue(void* para);

    void SaveImage(std::shared_ptr<CameraData> data);
    friend void t_SaveCameraImage(void* para, std::shared_ptr<CameraData> data);
private:

    //用来存储三台相机数据的容器//
    std::mutex m_DataMtx_;
    std::queue<std::shared_ptr<CameraData>> m_QueCamData_;
    std::condition_variable m_DataVar_;
    bool m_bQueExit_ = false;
    std::shared_ptr<SThreadPool> m_Pool_;
    std::future<void> m_fuProcessDataQue_;
};

实现文件中,重点关注函数t_ProcessDataQueue(void* para);同时这段代码还包括一种有效退出类内线程的方式,请看析构函数部分。

//实现文件
Sensor::Sensor()
{
    m_fuProcessDataQue_ = std::async(std::launch::async, &Sensor::t_ProcessDataQueue, this, nullptr);

    unsigned long hardwares = std::thread::hardware_concurrency();
    m_Pool_ = std::make_shared<SThreadPool>(hardwares);
}

Sensor::~Sensor()
{
    {
        std::unique_lock<std::mutex> locker(m_DataMtx_);
        m_bQueExit_ = true;
    }
    m_DataVar_.notify_one();
    m_fuProcessDataQue_.get();
}

int WINAPI s_ManagaGetImageCallBack(void* _context, void* _system, void* _data)
{
    Sensor* pThis = (Sensor*)_context;
    std::shared_ptr<CameraData> data = std::make_shared<CameraData>();

    //将从相机返回出来的数据组装成CameraData.....
    {
        std::unique_lock<std::mutex> lock(pThis->m_DataMtx_);
        pThis->m_QueCamData_.push(data);
    }
    pThis->m_DataVar_.notify_one();//通知另外一个线程进行数据的处理
    return 0;
}

void Sensor::t_ProcessDataQueue(void* para)
{
    std::shared_ptr<CameraData> 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();

                //process  camera data//
                //01 单线程方式存数据
                SaveImage(tempdata);

                //02 多线程的方式存数据//
                m_Pool_->enqueue(t_SaveCameraImage, this, tempdata);
            }
        }
        catch (const std::exception& e)
        {
            std::cout << e.what() << "\n";
        }


        if (m_bQueExit_)
        {
            break;
        }
    }
}


void Sensor::SaveImage(std::shared_ptr<CameraData> data)
{
    //保存相机
    //do want you want
}

void t_SaveCameraImage(void* para, std::shared_ptr<CameraData> data)
{
    //保存相机数据
    //do want you want
}

作为数据采集程序,这段代码非常适用。任何传感器的数据我都能用一个容器先接着,然后另外一个线程处理从这个容器中弹出来的数据。如果采用回调的方式获取传感器数据,这种方式还不堵塞回调。既然作为一种通用的方式,这段代码当然可以用模板类进行改进。笔者尝试着写了一个模板类,目前测试有效,下一篇文章公布模板代码。

欢迎大牛们与我进行交流探讨,如果对上述代码有疑问或者缺少某个头文件(如SThreadPool,这是一个线程池模板类),请扫码加我微信,备注“C++”。


WOODS

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342