QT循环队列实时处理数据(二)

         上一篇多线程介绍的是,QT多线程处理机制,这篇,将对接收数据,实时处理进行分析。

         QT通过socket通信,从接收缓冲区中读取数据,交给线程进行处理,那么问题来了,如果线程还没有处理完数据,则线程就没有办法继续从缓冲区中取数,那么当数据量过大的时候,缓冲区会满,继而被覆盖,从而造成数据的丢失。那么如何将数据存储在某个特定的空间内,并且让其他线程进行读取。这个是线程通信的问题,这个问题有多种方式,一种是操作系统课本上,通过线程同步、互斥、信号量这三种机制实现线程通信,或者就是通过循环队列的方式,完成线程通信。

         这篇主要介绍的是第二种方式,即循环队列的方式,进行通信。

         循环队列的实现方式,通过全局变量定义一个大的数组,同时,定义两个读写指针,这个指针不是语言中指针这个类型,可以理解成,两个标志位,记录读和写的位置,通过这种方式,可以实现一个循环队列的基本模型。如下图:


         write表示写指针,read表示读指针。我们将从socket缓冲区接收到的数据,缓存到队列中,将写指针向后移动,另外一个线程,操作读指针,不断跟随写指针,将数据取出,处理。下面把代码贴上来供大家参考:

MyThread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QDebug>
#include "basetype.h"
#include "mythreadstore.h"

/**
 * @brief The MyThreadRecv class
 * 该类负责接收从tcp读取到的数据。并将数据存储到缓冲区中
 */
class MyThreadRecv
{
public:
    MyThreadRecv();
    ~MyThreadRecv(){};

    void RecvMsg(const BYTE *data, int len);            ///< 接收数据,存入循环队列

};

/**
 * @brief The MyThread class
 * 处理数据的线程
 */
class MyThread: public QThread
{
public:

public:
    MyThread();
    ~MyThread(){};

    void init();
    void run();                 ///< 任务执行


private:
    volatile bool stopped;
    int Flag;
    MythreadStore *mythreadstore;
};

#endif // MYTHREAD_H
MyThread.cpp
#include "mythread.h"

BYTE Queue1[(1024 * 500)] = {0};            ///< 循环消息队列
int wReadPoint = 0;                         ///< 读指针
int wWritePoint = 0;                        ///< 写指针


MyThreadRecv::MyThreadRecv()
{

}

void MyThreadRecv::RecvMsg(const BYTE *data, int len)
{
    qDebug()<<"I will gointo for";
    for(int iNum = 0; iNum < len; iNum++) {
        /**
         * @brief tempWReadPoint
         * 存储,到程序执行到此处的时候,wReadPoint的值,因为线程一直在执行,很有可能执行到这步的时候,wReadPoint的值被改变。
         */
        int tempWReadPoint = wReadPoint;
        if((wWritePoint + 1) % (1024 * 500) == tempWReadPoint) {
            /**
             * 队列已满
             */
            continue;
        }
        /**
         * 处理队列不满的情况
         */
        Queue1[wWritePoint % (1024 * 500)] = data[iNum];
        wWritePoint = (wWritePoint +1) % (1024 * 500);


    }
    qDebug()<<"After for";
}

void MyThread::init()
{
    start();
}

MyThread::MyThread()
{
    stopped = false;
    Flag = 0;
    mythreadstore = new MythreadStore();
}

void MyThread::run()
{
    qDebug()<<"In run";
    int iFlag = 0;              ///< 标志位
    int iNum = 0;
    BYTE NeedDealdata[200] = {0};
    while(!stopped) {
        /**
         * @brief itempWritePoint
         * 存储,到程序执行到此处的时候,wWritePoint的值,因为线程一直在执行,很有可能执行到这步的时候,wWritePoint的值被改变。
         */
        int itempWritePoint = wWritePoint;
        if((wReadPoint) % (1024 * 500) != itempWritePoint) {
            /**
             * 队列不空
             */

            if((0 != Queue1[(wReadPoint - 2) % (1024 * 500)]) && (0x5A == Queue1[(wReadPoint - 1) % (1024 * 500)]) && (0x54 == Queue1[(wReadPoint) % (1024 * 500)])) {
                /**
                 * 找帧头
                 */
                iNum = 0;
                NeedDealdata[iNum++] = Queue1[(wReadPoint -1) % (1024 * 500)];
                NeedDealdata[iNum++] = Queue1[(wReadPoint) % (1024 * 500)];
                wReadPoint = (wReadPoint + 1) % (1024 * 500);
                iFlag = 1;

            }

            if((0 != Queue1[(wReadPoint - 2) % (1024 * 500)]) && (0x5A == Queue1[(wReadPoint - 1) % (1024 * 500)]) && (0xFE == Queue1[(wReadPoint) % (1024 * 500)]) && (1 == iFlag)) {

                NeedDealdata[iNum++] = Queue1[(wReadPoint) % (1024 * 500)];
                wReadPoint = (wReadPoint + 1) % (1024 * 500);
                qDebug()<<"I will store msg || iNum = " + QString::number(iNum);
                /**
                 * 找到需要处理的数据,处理数据
                 */
                mythreadstore->StoreMsgDeal(NeedDealdata, iNum);
                memset(NeedDealdata, '\0', sizeof(NeedDealdata));

                iFlag = 0;
                iNum = 0;

            }

            if(1 == iFlag) {
                NeedDealdata[iNum++] = Queue1[(wReadPoint) % (1024 * 500)];
                wReadPoint = (wReadPoint + 1) % (1024 * 500);
            } else {
                wReadPoint = (wReadPoint + 1) % (1024 * 500);
            }

        }
        usleep(10);

    }
}
        上面两段代码中,存在两个类,MyThreadRecv和MyThread,前者负责存储从socket中获取到的数据,后面这个类负责从队列中读取数据,并且处理。这样的机制,能够有效的处理循环队列中的数据,从而达到实时处理数据,并且保证数据准确性和实时性的问题,但是一个重点是,需要考虑什么时候队列满,什么时候队列空,这个问题是设计这个循环队列并且处理的关键,需要根据问题仔细的去分析,然后设计。

        对于循环队列的基本内容,这里就不做详细的描述,因为比较简单,可以自行查找数据结构相关的内容。



  • 18
    点赞
  • 107
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
Qt中使用消息队列(也称为事件队列)传递数据非常常见,特别是在多线程编程中。下面是一个简单的示例,展示如何在两个线程之间使用消息队列传递数据: ```cpp #include <QCoreApplication> #include <QThread> #include <QEvent> #include <QEventLoop> #include <QDebug> // 自定义事件类型,用于传递数据 class MyEvent : public QEvent { public: static const QEvent::Type EventType; MyEvent(int value) : QEvent(EventType), m_value(value) {} int value() const { return m_value; } private: int m_value; }; const QEvent::Type MyEvent::EventType = static_cast<QEvent::Type>(QEvent::registerEventType()); // 生产者线程 class ProducerThread : public QThread { public: void run() override { for (int i = 0; i < 10; ++i) { QCoreApplication::postEvent(qApp, new MyEvent(i)); msleep(1000); // 模拟耗时操作 } } }; // 消费者对象 class ConsumerObject : public QObject { public: ConsumerObject() { moveToThread(&m_thread); m_thread.start(); } ~ConsumerObject() { m_thread.quit(); m_thread.wait(); } // 事件处理函数,处理自定义事件类型 bool event(QEvent *event) override { if (event->type() == MyEvent::EventType) { MyEvent *myEvent = static_cast<MyEvent*>(event); qDebug() << "Received value:" << myEvent->value() << "on thread:" << QThread::currentThread(); return true; } return QObject::event(event); } private: QThread m_thread; }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 创建生产者线程 ProducerThread producer; producer.start(); // 创建消费者对象 ConsumerObject consumer; return a.exec(); } ``` 在上面的示例中,我们创建了一个自定义事件类型`MyEvent`,用于传递数据。生产者线程`ProducerThread`向消息队列中发送事件,而消费者对象`ConsumerObject`则在其自己的线程中,通过重载`event()`函数处理这些事件。当一个`MyEvent`事件被消费者对象接收时,它会打印出事件的值,并指出当前所在线程。 需要注意的是,在Qt中发送事件需要使用`QCoreApplication::postEvent()`函数,该函数可以将事件添加到应用程序的事件队列中。在消费者对象中,我们必须将它移动到一个新线程中,并在该线程中启动事件循环,以便可以接收事件。 此外,请注意,如果您使用Qt的信号和槽机制来传递数据,则不需要使用消息队列。消息队列通常用于在多个线程之间传递数据,而信号和槽机制则可在同一线程内传递数据

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值