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

2023-05-16

文章目录

  • 1. C++ queue 队列基本用法
  • 2. Qt QQueue 队列基本用法
  • 3. Qt QQueue 多线程队列
  • 4. Qt BlockingQueue 自定义线程安全的阻塞队列

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;
}

♦ 打印: ·

在这里插入图片描述

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();
}

♦ 打印: ·

在这里插入图片描述

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();
}

♦ 运行结果:

在这里插入图片描述

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

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

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

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

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

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

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

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

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

在这里插入图片描述

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

#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();
}

♦ 运行结果:

在这里插入图片描述

上述包含一个生产者线程和两个消费者线程,生产者线程往队列中插入10个整数,每插入一个元素后暂停0.5秒。两个消费者线程不断从队列中取出元素,并输出当前线程的ID和取出的元素值。 当队列为空时,消费者线程会进入等待状态,直到有其他线程往队列中插入元素。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt QQueue 安全的多线程队列、阻塞队列 的相关文章

  • Linux设备驱动思想在STM32编程中的应用

    这几天看了一下Linux设备驱动 xff0c 发现这套思想其实也可以用在普通的单片机编程上 这种思想较好的分割了驱动层和应用层的任务 xff0c 方便分层开发 以前 xff0c 我们开发STM32驱动的时候 xff0c 会给设备写一套函数来
  • 36.【linux驱动】spi framebuffer驱动(切换并显示虚拟终端)

    1 framebuffer驱动 2 spi framebuffer驱动 3 spi framebuffer驱动 切换并显示虚拟终端 切换终端输出 接这上一节 spi framebuffer驱动实现了 xff0c 但是只有刷屏 6个虚拟终端并
  • ubuntu 移除PPA

    ubuntu 移除PPA 问题描述解决方案1 移除PPA源2 移除key3 查看那些包被替换4 从官方源下载包并替换5 测试是否替换成功 总结反思 问题描述 试图在ubuntu 20 04上安装Phalcon框架 xff0c 但是发现版本不
  • django内置的密码加密与解密

    Django 内置的User类提供了用户密码的存储 验证 修改等功能 xff0c 默认使用pbkdf2 sha256方式来存储和管理用的密码 django通过PASSWORD HASHERS来设置选择要使用的算法 xff0c 列表的第一个元
  • TF坐标变换的学习

    官方教程 xff1a http wiki ros org tf ROS中的很多软件包都需要机器人发布tf变换树 xff0c 那么什么是tf变换树呢 xff1f 抽象的来讲 xff0c 一棵tf变换树定义了不同坐标系之间的平移与旋转变换关系
  • Docker 服务端口一览

    最近研究微服务 xff0c 使用Docker来进行部署应用 说实话docker是个好东西 xff0c 只要编写好Dockerfile文件和docker compose yml文件 xff0c 便能快速启动并运行相关服务 调试过程中查看服务可
  • 鱼眼镜头的成像原理到畸变矫正(完整版)

    最近刚接触鱼眼相机 xff0c 发现网上资料还是比较零散的 xff0c 于是把搜罗到的资料汇总梳理了一下 这里推荐大家直接看链接6的论文 xff0c 从成像模型到畸变矫正整个过程讲的比较清楚 xff0c 网上很多版本其实都是根据这两篇论文来
  • STM32通过广和通ADP-L610-Arduino进行TCP/IP通信

    STM32通过广和通L610进行TCP IP通信 一 写在前面 本次参加嵌入式大赛 xff0c 使用了广和通的ADP L610 Arduino板子进行通信 项目要求大概是本地上传数据到服务器 xff0c 服务器接收后发送给客户端 xff0c
  • Visual Studio Code Git版本控制 更改语言成英文

    一 初始化git库 新版vscode只能打开一个文件夹 xff0c 当你打开这个文件夹后 xff0c 再点击左边的git控制按钮 xff0c 就会初始化该文件夹为git工作目录 xff0c 如果已经有git控制 xff0c 则不会改变 在v
  • STM8S003F3 开发环境搭建

    硬件相关 芯片介绍 型号 xff1a STM8S003F3P6 xff0c 用的不是ARM内核 STM32用的是ARM xff0c 而是意法半导体自己生产的高性能8位内核 xff1a STM8AF 主要针对汽车电子应用 xff0c 如 xf
  • 教你写Makefile(很全,含有工作经验的)

    原文 转载文 Makefile 值得一提的是 xff0c 在Makefile中的命令 xff0c 必须要以 Tab 键开始 什么是makefile xff1f 或许很多Winodws的程序员都不知道这个东西 xff0c 因为那些Window
  • 与JWT的不解之缘

    jar xff1a maven lt dependency gt lt groupId gt io jsonwebtoken lt groupId gt lt artifactId gt jjwt lt artifactId gt lt v
  • 连接服务器报错:Key exchange was not finished, connection is closed.

    解决方案 xff1a 在 etc ssh sshd config最后添加如下行内容解决问题 KexAlgorithms diffie hellman group1 sha1 diffie hellman group14 sha1 diffi
  • ros多线程管理

    单线程Spinning ros spin 是最简单的单线程自旋 它会一直调用直到结束 用法 ros spin ros spinOnce 另一个单线程spinning是ros spinOnce 它定期调用等待在那个点上的所有回调 用法 ros
  • (每日一读2019.10.24)一种基于通用优化方法的多传感器全局里程计估计框架(VINS-Fusion)

    参考博文 萌新学VINS Fusion 一 特征跟踪 萌新学VINS Fusion 二 特征跟踪 摘要 精确的状态估计是自主机器人的一个基本问题 为了实现局部精确和全局无漂移状态估计 通常将具有互补特性的多个传感器融合在一起 局部传感器 摄
  • (每日一读2019.10.25)一种基于通用优化方法的多传感器局部里程计估计框架(VINS-Fusion)

    摘要 为了提高机器人的鲁棒性和自主性 越来越多的传感器被安装在机器人上 我们已经看到了不同平台上安装的各种传感器套件 例如地面车辆上的立体摄像机 手机上带有IMU 惯性测量单元 的单目摄像机以及空中机器人上带有IMU的立体摄像机 虽然过去已
  • Gazebo模型下载以及配置--解决Gazebo黑屏原因

    前往ExBot ROS专区下载Gazebo模型 https bitbucket org osrf gazebo models downloads 下载后把文件放在 gazebo下的models文件夹中 span class token fu
  • 相机内外参数以及畸变参数

    关于大佬们的一些见解 下面是引用知乎的一段文字 xff1a 我们从单目视觉说起 平时我们都说要做视觉识别 测量云云 xff0c 然后我们就会去拍照 xff0c 再对数字图像做各种处理 xff0c 颜色处理 灰度化 滤波 边缘检测 霍夫变换
  • cmake学习4--自定义编译选项

    CMake 允许为项目增加编译选项 xff0c 从而可以根据用户的环境和需求选择最合适的编译方案 例如 xff0c 可以将 MathFunctions 库设为一个可选的库 xff0c 如果该选项为 ON xff0c 就使用该库定义的数学函数
  • ROS与C++学习1

    ROS与C 入门教程 构建工作空间 构建Catkin包 搭建开发环境 catkin make 编写简单发布节点和订阅节点 编写简单服务端和客户端 使用类方法作为回调函数 使用Timers类 编写高级的发布器和订阅器 Callbacks和Sp

随机推荐

  • IAR的UI界面优化

    显示行数 Tools Options 点击 Editor Tab size xff1a 设置Tab键占用多少个空格Indent size xff1a 应该是设置过行时缩进多少个空格Insert tab xff1a 选了之后在删除Tab时 x
  • MYNTEYE小觅双目摄像头深度版+VINS测试

    小觅双目深度版性能分析 今年 xff08 18年 xff09 11月9号小觅智能科技的深度版双目相机上市 xff0c 于是我在12月初花了2999软妹币购买了120度视角的相机 其中我比较感兴趣的是 双目 43 惯导 43 结构光 的多传感
  • QT+ROS开发

    Qt Creator for ROS 如果想在Qt上进行ros包的开发和GUI界面开发 建议采用下面的方法 http fumacrom com 1mipW Setup Qt Creator for ROS Setup Ubuntu to a
  • PX4、APM无人机仿真连接QGC地面站记录(udp连接、更改home点等)

    文章目录 一 PX41 gazebo 仿真2 连接地面站3 更改 Home点 二 APM 仿真1 执行仿真指令2 连接地面站3 更改 Home 点 本文仅记录仿真指令 xff0c 搭建安装不在此 一 PX4 首先给飞控源码和子目录权限 sp
  • LeetCode 解题笔记(一)总

    文章目录 一 常用技巧二 常用翻译三 题目x 其他9 回文数 2021 12 0911 盛最多水的容器 2022 01 0515 三数之和 2022 01 14 17 电话号码的字母组合 2022 01 1520 有效的括号 2021 12
  • LeetCode 解题笔记(二)数组篇

    文章目录 一 基础篇26 删除排序数组中的重复 2022 01 16122 买卖股票的最佳时机 II 2022 01 17189 轮转数组 2022 01 18217 存在重复元素 2022 01 19136 只出现一次的数字 2021 1
  • LeetCode 解题笔记(四)链表

    文章目录 一 总结二 题目237 删除链表中的节点 xff08 2022 03 10 xff09 19 删除链表的倒数第 N 个结点 xff08 2022 03 11 xff09 206 反转链表 xff08 2022 03 18 xff0
  • QT Quick QML 实例之 Popup 弹出界面

    QT Quick QML 实例之 Popup 弹出界面 一 演示二 实现过程1 居中弹出2 正下方弹出 所有的热爱都要不遗余力 xff0c 真正喜欢它便给它更高的优先级 xff0c 和更多的时间吧 xff01 GIT工程文件在这里 QmlL
  • QGC(GGroundControl) 系统核心架构图

    关于QGC地面站其它文章请点击这里 QGC地面站 UML 核心类图 xff1a xff08 点击图片放大看效果更好 xff09 核心系统分析图 xff1a xff08 点击图片放大看效果更好 xff09 工程结构 xff1a 整个 QGC
  • Qt 国际化翻译,函数外部字符串、Map 翻译(QT_TRANSLATE_NOOP)

    文章目录 1 Qt 的翻译流程2 利用 QT TRANSLATE NOOP 翻译 GitHub 源码 QmlLearningPro xff0c 选择子工程 xff1a TranslationsDemo pro QML 其它文章请点击这里 Q
  • IAR新建工程

    下载库函数 本文介绍基于 IAR 43 官方标准固件库 xff0c 来新建 STM8S003F 工程 xff0c STM8S 的标准固件库可以到 ST 的官方网站中找到并下载 xff1a ST官网 1 在搜索栏上搜索 STM8S003F x
  • RTSP 推流和拉流记录(运行代码)

    文章目录 1 RTSP 推流2 RTSP 拉流 1 RTSP 推流 用C 43 43 11 实现的RTSP服务器和推流器 xff0c 链接如下 RtspServer GitHub原地址 xff1a https github com PHZ7
  • FFmpeg 中 RTSP推流桌面和Android设备延时测试

    文章目录 1 FFMPEG 推流 xff1a 1 1 FFmpeg 源码准备1 2 RTSP 推流服务器 2 执行流程2 1 启动服务器2 2 执行桌面推流2 3 播放 3 安卓测试 1 FFMPEG 推流 xff1a 1 1 FFmpeg
  • Windows 下 GitKraken 6.5.1免费版本安装

    文章目录 1 安装 6 5 1 版本2 更换快捷方式3 登录 用过 GitKraken 都说好 xff0c 不过 xff0c GitKraken 从 6 5 3 版本开始收费 xff0c 它的最后一个免费版本是 6 5 1 xff0c 当你
  • QT 中的多线程之 moveToThread

    文章目录 1 概述2 方法描述3 代码 xff1a 4 运行结果5 注意事项6 结语 1 概述 在 Qt 中 xff0c 多线程也被广泛用于实现后台任务 异步操作 多任务处理等功能 通过使用多线程 xff0c 可以提高程序的响应性和用户体验
  • QT 多线程之继承 QThread

    文章目录 1 概述2 方法描述3 代码 xff1a 4 运行结果5 结语 1 概述 在 Qt 中 xff0c 可以使用 QThread 的两种方式来创建和控制线程 xff1a 继承 QThread 类和使用 QObject moveToTh
  • Qt 多线程同步:互斥锁QMutextLocker 、读写锁 QReadWriteLock、信号量 QSemaphore、 条件变量QWaitConditio、QThread::wait()

    文章目录 1 Qt 多线程为什么需要同步机制 lt font gt 2 多线程有哪些同步机制 2 1 互斥锁 xff08 QMutex xff09 2 2 读写锁 xff08 QReadWriteLock xff09 2 3 信号量 xff
  • Windows下 ffmpeg 的 “Protocol not found“ 的解决

    文章目录 1 问题描述2 排查方法记录2 1 检查代码中编码器是否安装2 2 确定ffmpeg版本号2 3 打印编译参数2 4 查看运行中调用dll 1 问题描述 调用ffmpeg库中 xff0c 如果使用 avformat open in
  • Qt 智能指针介绍: QSharedPointer、QWeakPointer 、QScopedPointer 、QPointer(附实例)

    文章目录 1 概述2 Qt 中有几种智能指针 xff1f 2 1 QSharedPointer 实例2 2 QSharedPointer 与 QWeakPointer 实例2 3 QScopedPointer 实例2 4 QPointer
  • Qt QQueue 安全的多线程队列、阻塞队列

    文章目录 1 C 43 43 queue 队列基本用法2 Qt QQueue 队列基本用法3 Qt QQueue 多线程队列4 Qt BlockingQueue 自定义线程安全的阻塞队列 1 C 43 43 queue 队列基本用法 在C