在项目开发过程中,有时会遇到,扫描数据时,一边是扫描添加数据,一边是显示取数据或对数据进行添加删除操作,如何才能保证数据的同步,并且不会引发操作数据时的异常呢,Qt中可以使用QQueue来实现这种方便,使用线程加互斥来配合使用,达到这种效果,例如以消息为例,扫描获取消息时添加到消息队列中,消息队列处理完了再取下一个数据,有时消息来不及处理,扫描到的消息就一直存在消息队列中,避免消息处理遗漏了。
#ifndef CMESSAGEQUEUETHREAD_H
#define CMESSAGEQUEUETHREAD_H
#include <QThread>
class CMessageQueueThread : public QThread
{
Q_OBJECT
public:
CMessageQueueThread();
~CMessageQueueThread();
void run();
void stop();
bool stopState();
private:
bool m_bStop;
signals:
void signalQueueWebSocketMessageData(const QString &webSocketMsg);
};
#endif // CMESSAGEQUEUETHREAD_H
#include "CMessageQueueThread.h"
#include "CMainControl.h"
#include <QDebug>
CMessageQueueThread::CMessageQueueThread():
m_bStop(false)
{
qDebug()<<"CMessageQueueThread id:"<<currentThreadId();
}
CMessageQueueThread::~CMessageQueueThread()
{
qDebug()<<"~CMessageQueueThread id:"<<currentThreadId();
}
void CMessageQueueThread::run()
{
CMainControl* pMainControl = CMainControl::getInstance();
qDebug()<<"CMessageQueueThread RUN======================";
while(!m_bStop){
pMainControl->mutexM.lock();
while(!m_bStop && pMainControl->m_qQueueMsg.empty())//队列为空,等待
{
pMainControl->m_waitCondition.wait(&pMainControl->mutexM);
}
if(m_bStop){
pMainControl->mutexM.unlock();
break;
}
QString msg= pMainControl->m_qQueueMsg.dequeue();
pMainControl->mutexM.unlock();
qDebug()<<"signalQueueWebSocketMessageData===="<<msg;
emit signalQueueWebSocketMessageData(msg);
}
qDebug()<<"exit thread CMessageQueueThread id:"<<currentThreadId();
}
void CMessageQueueThread::stop()
{
m_bStop = true;
}
bool CMessageQueueThread::stopState()
{
return m_bStop;
}
#ifndef CMAINCONTROL_H
#define CMAINCONTROL_H
#include <QQueue>
#include <QMutex>
#include <QObject>
#include <QWaitCondition>
#include "CMessageQueueThread.h"
class CMainControl : public QObject
{
Q_OBJECT
public:
explicit CMainControl(QObject *parent = nullptr);
static CMainControl* getInstance()
{
if(m_pInstance == nullptr)
m_pInstance = new CMainControl();
return m_pInstance;
}
~CMainControl();
friend class CMessageQueueThread;
void initData();
int getMessageCount();
void stopMsgTask();
signals:
void signalRecevieMessage(const QString &message);
public slots:
void slotAddQueueMessageData(const QString &message);
void slotParseMessageData(const QString &message);
private:
static CMainControl *m_pInstance;
QMutex mutexM;
QWaitCondition m_waitCondition;
QQueue<QString> m_qQueueMsg;
CMessageQueueThread* m_pMsgTaskThread;
};
#endif // CMAINCONTROL_H
#include "CMainControl.h"
#include <QDebug>
#include <QCoreApplication>
#include <QApplication>
CMainControl* CMainControl::m_pInstance = new CMainControl();
CMainControl::CMainControl(QObject *parent)
: QObject(parent)
, m_pMsgTaskThread(nullptr)
{
}
CMainControl::~CMainControl()
{
qDebug() << "Destructor() ===============~CMainControl=";
stopMsgTask();
delete m_pMsgTaskThread;
m_pMsgTaskThread = nullptr;
}
void CMainControl::initData()
{
m_pMsgTaskThread = new CMessageQueueThread();
connect(m_pMsgTaskThread, &CMessageQueueThread::signalQueueWebSocketMessageData,
this, &CMainControl::slotParseMessageData, Qt::BlockingQueuedConnection);
//阻塞连接等slotParseMessageData函数执行完了再发下一个信号
m_pMsgTaskThread->start();
}
void CMainControl::slotParseMessageData(const QString &message)
{
qDebug()<<"CMainControl::slotParseMessageData:================" << message;
}
void CMainControl::slotAddQueueMessageData(const QString &message)
{
mutexM.lock();
qDebug()<<"CMainControl::slotAddQueueMessageData:==============message.size=====" << message.size();
m_qQueueMsg.enqueue(message);
m_waitCondition.notify_all();
mutexM.unlock();
}
int CMainControl::getMessageCount()
{
return m_qQueueMsg.size();
}
void CMainControl::stopMsgTask()
{
if(!m_pMsgTaskThread||m_pMsgTaskThread->stopState())
return;
qDebug() << "CMainControl::stopMsgTask========================================" << __LINE__;
if(m_pMsgTaskThread)
m_pMsgTaskThread->stop();
m_waitCondition.notify_all();
m_qQueueMsg.clear();
m_pMsgTaskThread->deleteLater();
m_pMsgTaskThread = nullptr;
qDebug() << "CMainControl::stopMsgTask=======2=================================" << __LINE__;
}
启动消息队列
g_pMainControl->initData();
添加消息
g_pMainControl->slotAddQueueMessageData(str);
处理消息
slotParseMessageData(const QString &message)
如果这条消息没有处理完,后面的消息一直存在队列中,处理完一条再取下一条,保证消息不漏掉。