在仿真引擎中设计过程中比较重要的内容有时间同步控制、业务数据的流转处理。
1.时间同步专门启动一个线程用来计时,采用C++11高精度时间库
std::chrono::high_resolution_clock::now()详见之前的文章C++中高精度时间的记录控制
在时间线程中,处理线程中不能再进行任何其他的操作,否则会影响时间的精度。
当时间间隔到达规定的时间间隔时(10ms),就会触发相应的事件,这个的触发事件就是设置变量值(每次定时器开始的时候,设置变量为false,当时间间隔到的时候设置变量为true,在变量从false到true的过程中所运行的时间就是10ms,设置完成true之后,会再次设置成false,进入下一个时间间隔循环)。
其他需要时间的线程当读取到这个变量为true时,开始执行线程中的其他代码工作(更新界面线程开始更新界面数据、生成者线程开始生产数据等)。其他的线程是如何读取到这个变量值发生了变化了呢?除了时间线程以外,其他的线程都是实时的工作状态,也就是一个“死循环”,在循环中不停的检测这个变量的值是否变为true,一旦检测到这个变量发生了变化,就会立马执行。执行完成之后,会再次等待变量变成true。
2.数据流转数据流转模型采用的是【生产者-消费者】模型,具体模型的含义大家可以自行查找资料,这方面的资料很多。简单来说就是实体产生数据,把产生的数据放到数据队列中,消费者从数据队列中获取到数据进行出来,处理完成之后,数据队列就会删除这条数据。
单独启动一个数据队列的维护线程,这个线程的主要目的就是删除已经被处理过的数据。
数据队列管理:
#pragma once #include#include class ItemData; //缓冲数据管理 #define CacheDataMgr() (CacheDataManager::getInstance()) class CacheDataManager { private: CacheDataManager(); static CacheDataManager* _instance; public: ~CacheDataManager(); static CacheDataManager* getInstance(); void clearInvalidData(); void addItemData(ItemData* data); int dataCount(); void setChange(bool b) { _isChange = b; } bool&getChange() { return _isChange; } ItemData* getFrontData(); private: std::queue _cacheDataList;//数据队列 QMutex _mutex;//写入锁 bool _isChange = false; //数据队列是否发生变化 };
数据队列管理线程:
#include#include "DataThread.h" #include "CacheDataManager.h" DataThread::DataThread(QObject *parent) : QThread(parent) { } DataThread::~DataThread() { } void DataThread::run() { while (true) { usleep(1); //1.数据列表发生了变化 if (CacheDataMgr()->getChange()) { qDebug() << QStringLiteral("数据队列数量:%1").arg(CacheDataMgr()->dataCount()); CacheDataMgr()->setChange(false); } //2.清除掉无用的数据 CacheDataMgr()->clearInvalidData(); } }
生成者线程:
#include#include #include "ProductThread.h" #include "ItemDataString.h" #include "ItemDataInt.h" #include "CacheDataManager.h" ProductThread::ProductThread( QObject *parent) : QThread(parent) { } ProductThread::~ProductThread() { } void ProductThread::run() { while (true){ msleep(100); int randNum = QRandomGenerator::global()->bounded(2);//生成一个0和2之间的整数 ItemData* itemData = nullptr; if (randNum%2 == 0) {//如果是偶数 itemData = new ItemDataInt; qDebug() << QStringLiteral("线程ID:%1 产生整型数据").arg(QString::number(unsigned int(QThread::currentThreadId()))); } else {//奇数 itemData = new ItemDataString; qDebug() << QStringLiteral("线程ID:%1 产生字符串数据").arg(QString::number(unsigned int(QThread::currentThreadId()))); } //保存到缓存数据列表中 CacheDataMgr()->addItemData(itemData); } }
消费者线程:
#include#include "ConsumeThread.h" #include "CacheData/CacheDataManager.h" #include "CacheData/ItemData.h" ConsumeThread::ConsumeThread(QObject *parent) : QThread(parent) { } ConsumeThread::~ConsumeThread() { } void ConsumeThread::run() { while (true) { usleep(1); ItemData* frontData = CacheDataMgr()->getFrontData(); if (frontData == nullptr){ continue; } if (frontData->getValid()){ //获取队首数据,然后处理数据 qDebug() << QStringLiteral("消费者处理在时间%1产生的数据").arg(frontData->getDataProductTime()); //处理完成之后,数据就变得无效 frontData->setValid(false); } } }
运行程序,输出结果:
"数据队列数量:1" "消费者处理在时间2021-10-10 17:14:19.972产生的数据" "数据队列数量:0" "线程ID:34912 产生整型数据" "线程ID:25076 产生整型数据" "线程ID:1108 产生整型数据" "数据队列数量:3" "消费者处理在时间2021-10-10 17:14:20.082产生的数据" "消费者处理在时间2021-10-10 17:14:20.082产生的数据" "数据队列数量:2" "数据队列数量:1" "消费者处理在时间2021-10-10 17:14:20.082产生的数据" "数据队列数量:0" "线程ID:1108 产生整型数据" "线程ID:34912 产生整型数据" "线程ID:25076 产生字符串数据" "数据队列数量:3" "消费者处理在时间2021-10-10 17:14:20.190产生的数据" "消费者处理在时间2021-10-10 17:14:20.190产生的数据" "数据队列数量:2" "消费者处理在时间2021-10-10 17:14:20.190产生的数据" "数据队列数量:1" "数据队列数量:0" "线程ID:34912 产生整型数据" "线程ID:25076 产生字符串数据" "线程ID:1108 产生字符串数据" "数据队列数量:3" "消费者处理在时间2021-10-10 17:14:20.299产生的数据" "数据队列数量:2" "消费者处理在时间2021-10-10 17:14:20.299产生的数据" "消费者处理在时间2021-10-10 17:14:20.299产生的数据" "数据队列数量:1" "数据队列数量:0" "线程ID:1108 产生字符串数据" "线程ID:34912 产生整型数据" "线程ID:25076 产生字符串数据" "数据队列数量:3" "消费者处理在时间2021-10-10 17:14:20.408产生的数据" "消费者处理在时间2021-10-10 17:14:20.408产生的数据"
Demo下载



