Qt QQueue 安全的多线程队列、阻塞队列

这篇具有很好参考价值的文章主要介绍了Qt QQueue 安全的多线程队列、阻塞队列。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. C++ queue 队列基本用法

在C++中,queue是一个模板类,用于实现队列数据结构,遵循先进先出的原则。

♦ 常用方法: ·

queue<int> Q;            //定义一个int型队列
Q.empty();               //返回队列是否为空
Q.size();                //返回当前队列长度
Q.front();               //返回当前队列的第一个元素
Q.back();              	 //返回当前队列的最后一个元素
Q.push();                //在队列后面插入一个元素, 比如插入数字5: Q.push(5)
Q.pop();                 //从当前队列里,移出第一个元素

♦ 简单使用: ·

#include <iostream>
#include <queue>

using namespace std;

int main()
{
    // 创建一个queue对象
    queue<int> Q;

    // 向队列中添加元素
    Q.push(1);
    Q.push(2);
    Q.push(3);

    cout<<"queue empty?  "<<Q.empty()<<endl;
    cout<<"queue size:   "<<Q.size()<<endl;

    // 从队列中移除元素,并输出
    while (!Q.empty()) {
        int value = Q.front();
        Q.pop();
        cout << "Dequeued:" << value << endl;
    }

    return 0;
}

♦ 打印: ·

qt线程安全队列,QT 数据结构,qt,c++,开发语言,queue,多线程队列

2. Qt QQueue 队列基本用法

QQueue 继承与 QList

♦ 常用方法: ·

QQueue<int> QQ;         	 //定义一个int型队列

QQ.isEmpty();                //返回队列是否为空

QQ.size();                   //返回队列元素个数

QQ.clear();                  //清空队列

QQ.enqueue();                //在队列尾部添加一个元素, 比如插入数字5: QQ.enqueue(5)
/* 相当于
Q.push();                 
*/

QQ.dequeue();                //删除当前队列第一个元素,并返回这个元素
/* 相当于
Q.front();                   //返回当前队列的第一个元素
Q.pop();                     //从当前队列里,移出第一个元素
*/

QQ.head();                   //返回当前队列第一个元素
/* 相当于
Q.front();                   
*/

QQ.last();                   //返回当前队列尾部的元素
/* 相当于
Q.back();              	   
*/
T &  operator[]( int i );   //以数组形式访问队列元素

♦ 实例: ·

#include <QCoreApplication>
#include <QQueue>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建一个QQueue对象
    QQueue<int> QQ;

    // 向队列中添加元素
    QQ.enqueue(1);
    QQ.enqueue(2);
    QQ.enqueue(3);

    qDebug()<<"queue empty:  "<<QQ.isEmpty();
    qDebug()<<"queue size:  " <<QQ.size();
    qDebug()<<"queue head:  " <<QQ.head()  ;
    qDebug()<<"queue last:  " <<QQ.last()  << "\n";


    // 从队列中移除元素,并输出
    while (!QQ.isEmpty()) {
        int value = QQ.dequeue();
        qDebug() << "Dequeued:" << value;
    }

    return a.exec();
}

♦ 打印: ·

qt线程安全队列,QT 数据结构,qt,c++,开发语言,queue,多线程队列

3. Qt QQueue 多线程队列

在多线程编程中,由于QQueue并不是线程安全的,因此我们需要先使用互斥锁(QMutex)来保护队列。在读写队列时,我们需要获取互斥锁的锁定,以避免多个线程同时访问队列导致的数据竞争问题。

然后通过经典的生产者和消费者来看一个简单的示例程序,演示如何使用QQueue实现线程安全队列:

#include <QCoreApplication>
#include <QQueue>
#include <QMutex>
#include <QThread>
#include <QDebug>

// 定义线程安全队列类
template<typename T>
class ThreadSafeQueue
{
public:
    // 添加元素到队列尾部
    void enqueue(const T& value) {
        QMutexLocker locker(&m_mutex);
        m_queue.enqueue(value);
    }

    // 从队列头部移除一个元素,并返回它
    T dequeue() {
        QMutexLocker locker(&m_mutex);
        if (m_queue.isEmpty()) {
            return T();
        }
        return m_queue.dequeue();
    }

    // 返回队列是否为空
    bool isEmpty() const {
        QMutexLocker locker(&m_mutex);
        return m_queue.isEmpty();
    }

private:
    QQueue<T> m_queue;
    mutable QMutex m_mutex;
};

// 定义生产者线程类
class ProducerThread : public QThread
{
public:
    ProducerThread(ThreadSafeQueue<int>& queue)
        : m_queue(queue)
    {
    }

protected:
    void run() override {
        for (int i = 1; i <= 10; i++) {
            m_queue.enqueue(i);
            qDebug() << "Enqueued:" << i;
            msleep(500);
        }
    }

private:
    ThreadSafeQueue<int>& m_queue;
};

// 定义消费者线程类
class ConsumerThread : public QThread
{
public:
    ConsumerThread(ThreadSafeQueue<int>& queue)
        : m_queue(queue)
    {
    }

protected:
    void run() override {
        while (!isInterruptionRequested()) {
            if (!m_queue.isEmpty()) {
                int value = m_queue.dequeue();
                qDebug() << "Dequeued:" << value;
            }
            msleep(500);
        }
    }

private:
    ThreadSafeQueue<int>& m_queue;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建线程安全队列对象
    ThreadSafeQueue<int> queue;

    // 创建生产者线程对象和消费者线程对象
    ProducerThread producer(queue);
    ConsumerThread consumer(queue);

    // 启动线程
    producer.start();
    consumer.start();

    qDebug() << "F1";

    // 等待线程结束
    //在producer等待期间,  consumer run()也会运行 直到producer 运行完毕,main才能往下执行
    producer.wait();

    qDebug() << "F2";

    consumer.requestInterruption(); //相当于 ctrl + c 结束 consumer 线程
    qDebug() << "F3";
    consumer.wait();
    qDebug() << "F4";

    return a.exec();
}

♦ 运行结果:

qt线程安全队列,QT 数据结构,qt,c++,开发语言,queue,多线程队列

在上面的示例程序中,我们首先定义了一个模板类ThreadSafeQueue,用于实现线程安全队列。该类使用QMutex来保护QQueue对象,以实现线程安全。

接下来,我们定义了两个线程类ProducerThread和ConsumerThread,用于生产和
消费数据。

在ProducerThread中,我们循环向队列中添加元素,每隔500毫秒添加一个元素。在ConsumerThread中,我们循环从队列中取出元素,每隔500毫秒取出一个元素。在取出元素时,我们需要判断队列是否为空,避免出现异常情况。

其中:执行 producer.wait() 时, mian 中主线程将会被阻塞; 等到 producer 生产者运行完毕,才会唤醒;而 consumer 线程不受影响;

万一发生数据处理速度不匹配的情况呢?

  • 生产者休眠 500ms 消费者休眠500ms, 就是如上情况
  • 生产者休眠时间 < 消费者休眠时间, 那么生产者执行完毕后,消费者还未消费完就退出线程了,那么生产者必须暂停等待一下(阻塞生产者线程),以便等待消费者线程把累积的数据处理完毕
  • 生产者休眠时间 > 消费者休眠时间, 那么生产者执行完毕后,消费者也执行完毕了

真实的大数据情况下,如果生产者产出数据的速度大于消费者消费的速度,并且当生产出来的数据累积到一定程度的时候,那么生产者必须暂停等待一下(阻塞生产者线程),以便等待消费者线程把累积的数据处理完毕,反之亦然。在多线程环境下,我们每个程序员都必须去自己控制这些细节,尤其还要兼顾效率和线程安全,而这会给我们的程序带来不小的复杂度。

在 java 中有 BlockingQueue 阻塞队列,但是Qt 中似乎没有相关的阻塞队列,需要我们自己去自己控制这些细节

4. Qt BlockingQueue 自定义线程安全的阻塞队列

qt线程安全队列,QT 数据结构,qt,c++,开发语言,queue,多线程队列

以下定义一个简单的阻塞队列:

#include <QCoreApplication>
#include <QWaitCondition>
#include <QQueue>
#include <QMutex>
#include <QThread>
#include <QDebug>

template <typename T>
class BlockingQueue
{
public:
    BlockingQueue() {}
    void put(const T& value)
    {
        QMutexLocker locker(&m_mutex);
        m_queue.enqueue(value);
        m_condition.wakeOne();   //唤醒等待队列中的一个线程(来自wait)
    }
    T take()
    {
        QMutexLocker locker(&m_mutex);
        while (m_queue.isEmpty()) {
            m_condition.wait(&m_mutex);
        }
        return m_queue.dequeue();
    }
    bool isEmpty() const
    {
        QMutexLocker locker(&m_mutex);
        return m_queue.isEmpty();
    }
    int size() const
    {
        QMutexLocker locker(&m_mutex);
        return m_queue.size();
    }

private:
    QQueue<T> m_queue;
    mutable QMutex m_mutex;
    QWaitCondition m_condition;
};

这个 BlockingQueue类使用QMutex和QWaitCondition来保证线程安全,并实现了put、take、isEmpty和size等方法。其中,put方法用于往队列中插入元素,take方法用于从队列中取出元素,isEmpty方法用于判断队列是否为空,size方法用于获取队列中元素的数量。

在put方法中,我们首先获取了互斥锁,然后将元素插入到队列中,并通过QWaitCondition的wakeOne()方法唤醒一个等待线程(调用take()中的线程)。在take方法中,我们首先获取了互斥锁,然后在队列为空时调用QWaitCondition的wait()方法等待,直到有其他线程往队列中插入了元素并唤醒了当前线程。

mutable的作用是允许在const成员函数中修改BlockingQueue类的m_mutex和m_notEmpty成员变量。这是因为,生产者和消费者线程在往阻塞队列中添加或删除元素时,都需要对这两个成员变量进行修改。但是,由于take()和tryTake()方法都是const成员函数,因此如果不将m_mutex和m_notEmpty声明为mutable类型,编译器就会报错。

♦ 使用: ·

static BlockingQueue<int> queue;

class Producer : public QThread
{
public:
    void run() override
    {
        for (int i = 0; i < 10; ++i) {
            queue.put(i);
            qDebug() << "Producer thread: " << QThread::currentThreadId() << ", value: " << i;
            msleep(500); // sleep for 0.5 second

        }
    }
};

class Consumer : public QThread
{
public:
    void run() override
    {
        int value = 0;
        while (true) {
            value = queue.take();
            qDebug() << "Consumer thread: " << QThread::currentThreadId() << ", value: " << value;
        }
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Producer producer;
    Consumer consumer1, consumer2;

    producer.start();
    consumer1.start();
    consumer2.start();

    return a.exec();
}

♦ 运行结果:

qt线程安全队列,QT 数据结构,qt,c++,开发语言,queue,多线程队列

上述包含一个生产者线程和两个消费者线程,生产者线程往队列中插入10个整数,每插入一个元素后暂停0.5秒。两个消费者线程不断从队列中取出元素,并输出当前线程的ID和取出的元素值。 当队列为空时,消费者线程会进入等待状态,直到有其他线程往队列中插入元素。 文章来源地址https://www.toymoban.com/news/detail-563846.html

到了这里,关于Qt QQueue 安全的多线程队列、阻塞队列的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【基于Qt和OpenCV的多线程图像识别应用】

    这是一个简单的小项目,使用Qt和OpenCV构建的多线程图像识别应用程序,旨在识别图像中的人脸并将结果保存到不同的文件夹中。这个项目结合了图像处理、多线程编程和用户界面设计。 用户可以通过界面选择要识别的文件夹和保存结果的文件夹。然后,启动识别进程。图像

    2024年02月05日
    浏览(40)
  • PyQt应用程序中的多线程:使用Qt还是Python线程?

    多线程模块能够更加高效得完成任务,但是在PyQt 应用程序中实现多线程可以使用 Qt 的线程模块(QThread)或者 Python 的 threading 模块。两者各有优劣,具体选择取决于项目需求和个人偏好。下面我们将以案例来说明两种模块具体得优缺点。 1、问题背景 在 PyQt 应用程序中,编

    2024年02月22日
    浏览(55)
  • Qt实现简易的多线程TCP服务器(附源码)

    目录 一.UI界面的设计 二.服务器的启动 三.实现自定义的TcpServer类 1.在widget中声明自定义TcpServer类的成员变量 2.在TcpServer的构造函数中对于我们声明的m_widget进行初始化,m_widget我们用于后续的显示消息等,说白了就是主界面的更新显示等 四.实现自定义的TcpSocket类 1.TcpSocket.

    2024年04月17日
    浏览(78)
  • QT下的多线程TCP客户端和服务器

    qt下的QTcpSocket在同一个线程使用时没有问题的,但是如果进行跨线程,很容易出现问题。那么有什么方法可以跨线程进行使用吗? 答案是肯定的:使用QThread的movetothread可以完成扩线程接收。 首先是基于QTcpSocket的类 头文件tcpsocket.h 然后是cpp文件tcpsocket.cpp 再次基础上,创建

    2024年01月17日
    浏览(51)
  • 基于Qt的多线程TCP即时通讯软件的设计与实现

    本文将从涉及到主要技术开始,讲解使用Qt来实现一个支持多客户端链接的 多线程TCP服务器 及其 客户端 的设计与实现的解决方案。 注:本文使用的开发环境为Qt5.15.2, 使用MSVC2019_64编译器, C++11及以上 接下来我将会详细讲解客户端和服务端的设计与实现的关键细节。完整的源

    2024年01月16日
    浏览(49)
  • 掷骰子的多线程应用程序2基于互斥量的线程同步(复现《Qt C++6.0》)

    说明:在复现过程中出现两点问题(1)run()函数中对m_diceValued的赋值(2)do_timeOut()函数中没有对m_seq、m_diceValued进行定义。修改后的复现程序如下所示: 主线程: .h .cpp 工作线程: .h .cpp

    2024年02月07日
    浏览(84)
  • 5. QT环境下使用OPenCV(基于TCP实现摄像头图像数据的多线程传输)

    1. 说明 通常情况下对于图像数据的采集可以放在后端进行,采集到的图像数据如果有需要可以通过通信将数据传输到前端进行显示,这其中需要使用到TCP数据传输协议和QT下的多线程开发技术。 QT当中主线程一般是界面层次的,在主线程中执行耗时较长的数据操作,会引起界

    2024年02月11日
    浏览(63)
  • Qt扫盲-Reentrant和线程安全

    在整个文档中, Reentrant 和 thread-safe 术语用于标记类和函数,指明如何在多线程应用程序中使用它们: 一个 thread-safe的函数可以从多个线程同时调用,即使调用使用了共享数据,因为对共享数据的所有引用都是序列化的。 一个 Reentrant 函数也可以从多个线程同时调用Reentrant函

    2023年04月23日
    浏览(32)
  • Windows平台鼠标按下标题栏的阻塞问题研究(使用Qt框架)

    以下内容是Windows平台特有问题,其他平台可以忽略。 一直以来使用Qt开发桌面程序,拖拽移动窗口时,偶尔会发现明显的“掉帧”,以为是机器性能或者Qt框架的机制引起的刷新异常便没有在意。最近在使用QTimer定时在QWidget上渲染视频时,才发现比想象的更严重。 经过测试

    2024年02月11日
    浏览(52)
  • Qt学习:Qt 进程和线程之四,线程实际应用

    为了让程序尽快响应用户操作,在开发应用程序时经常会使用到线程。 对于耗时操作如果不使用线程,UI 界面将会长时间处于停滞状态,这种情况是用户非常不愿意看到的,我们可以用线程来解决这个问题。 大多数情况下,多线程耗时操作会与 UI 进行交互,比如:显示进度

    2024年02月13日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包