队列的讲解:C++队列的使用

article/2025/6/7 21:51:31

一.队列的介绍:

队列是C/C++中最基础的数据结构之一,队列本质上是一种线性表。它遵循着先进先出(fifo)的特点,在队列中一般在队尾插入,队头出队。这就相当于排队一样,刚入队的人需要排在队尾(rear),每次出队的都是在队首(front)。在实际开发中队列发挥着巨大的作用,比方说多线程数据传输、缓存数据的存储、中间件的设计等等。

从上面这张图我们可以看到,队尾入队了三个元素分别是1,2,3。1号数据最早入队、2号数据第二入队、3号数据最后入队。出队的时候,1号最早出队(pop1)、2号排在1号数据后面(pop2)、3号最后出队(pop3)。所以使用队列的时候,我们可以保证数据的顺序不会出现乱序的错误。

二.队列的用处:

队列常用于在多线程数据传输、数据解耦、缓存数据等方面。由于在大型的项目开发中,往往有许多线程同时运作。此时,许多线程之间需要进行数据的传递,所以此时我们就需要通过队列作为一条桥梁把数据从一个线程送到另外一个线程里面(如下图一就是队列在两个线程之间的通信)。线程一把数据按照顺序把数据包存储到Queue上、线程二、三也按照顺序从队列拿到数据。

                               (图一)

除了线程之间通信之外,队列还常用于数据量缓存方面。比方说,在音视频解码的时候,音视频数据会大量传入解码端。假设此时没有一个缓冲的时间,解码端可能会因为处理速度的问题,导致解码视频的时候会出现花屏、卡顿等问题。所以,此时我们就需要用队列进行缓冲,使其传输速度降下来,那解码端的解码压力就会大大降下来,此时解码出来的画面质量就会高很多,具体的流程如图二。

                                  (图二)

三.C++ STL队列的用法:

C++库已经提供了一套队列的api方便开发者进行开发,这样我们就不用重新再新造轮子去实现队列。下面我们就来看看我们用stl queue去实现队列:

3.1. queue的初始化:

#include <queue>

std::queue<object> object_queue;

初始化stl的queue,需要做两步第一步要包含<queue>头文件,#include<queue>;

第二步声明queue,std::queue<object> object_queue。里的<object>里面的object是任意类型的数据,也包括结构体的数据。

3.2.queue的操作api:

front()返回 queue 中第一个元素的引用。如果 queue 是常量,就返回一个常引用;如果 queue 为空,返回值是未定义的。

back()返回 queue 中最后一个元素的引用。如果 queue 是常量,就返回一个常引用;如果 queue 为空,返回值是未定义的。

push(const T& obj)在 queue 的尾部添加一个元素的副本。这是通过调用底层容器的成员函数 push_back() 来完成的。

push(T&& obj)以移动的方式在 queue 的尾部添加元素。这是通过调用底层容器的具有右值引用参数的成员函数 push_back() 来完成的。

pop()删除 queue 中的第一个元素。

size()返回 queue 中元素的个数。

empty()如果 queue 中没有元素的话,返回 true。

emplace()用传给 emplace() 的参数调用 T 的构造函数,在 queue 的尾部生成对象。

swap(queue<T> &other_q)将当前 queue 中的元素和参数 queue 中的元素交换。它们需要包含相同类型的元素。也可以调用全局函数模板 swap() 来完成同样的操作。

3.3.queue的demo

上面这个是一个简单的stl queue操作,先入队6个元素(0-5)。然后再连续出队pop,这里总共出队了4次,此时元素0 1 2 3全部出队并删除,所以打印front的元素是4。

四.多线程队列的框图:

上图是同一个典型的多线程入队,出队的过程。这里需要创建两个线程,一个是入队线程、一个是出队线程。入队线程主要是通过push的api向Queue的队尾插入数据,插入数据的同时通过pthread_cond_broadcast通知出队线程取出数据。此时出队线程正在等待入队线程的唤醒(pthread_cond_wait),若收到唤醒通知则让队列数据出队。

五.Linux多线程的基本API:

1. pthread_mutex_lock

int pthread_mutex_lock(pthread_mutex_t *mutex);

第一个传入参数:pthread_mutex_t结构体指针

功能:这个是互斥锁加锁功能,就是每次线程调用的时候都会把锁加上,使其保证访问数据的原子性,直到解锁为止。

2. pthread_mutex_unlock:

int pthread_mutex_unlock(pthread_mutex_t *mutex);

第一个传入参数:pthread_mutex_t结构体指针

功能:这个是互斥锁解锁功能,就是每次线程访问完资源的时候都会把锁解锁。

3. pthread_cond_broadcast

int pthread_cond_broadcast(pthread_cond_t *cond)

传入参数:pthread_cond_t的结构体指针

功能:唤醒所有正在pthread_cond_wait(线程等待)的线程

4. pthread_cond_wait:

int pthread_cond_wait (pthread_cond_t *__restrict __cond , pthread_mutex_t *__restrict __mutex)

第一个参数:pthread_cond_t的结构体指针

第二个参数:pthread_mutex_t结构体指针

功能线程等待并挂起,若被唤醒了,则直接跳出挂起状态。

在多线程里面所有的操作都需要上锁,包括出队、入队,或者其他的业务操作都需要上锁,保证数据的安全性。

六.推流项目中视频队列的实现:

这张图是视频队列实现的过程,VIDEO_QUEUE是一个类。这个类里面,封装了添加视频队列(putVideoPacketQueue)、获取视频队列数据(getVideoPacketQueue)、获取视频队列长度(getVideoQueueSize)。

3.1. VIDEO_QUEUE构造器

这里创建一个VIDEO_QUEUE的C++的构造器,C++构造器主要初始化了线程的量。包括:线程锁的初始化(pthread_mutex_init)、线程条件变量的初始化(pthread_cond_init)。

3.2. putVideoPacketQueue的讲解:

putVideoPacketQueue主要是video_data_packet_t入队的过程,入队前需要加锁pthread_mutex_lock。然后进行入队操作video_packet_queue.push(video_packet),入队完成之后再通知出队线程取出队列数据pthread_cond_broadcast,最后解锁pthread_mutex_unlock

3.3. getVideoPacketQueue的讲解:

getVideoPacketQueue主要是video_data_packet_t入队的过程,入队前需要加锁pthread_mutex_lock。然后判断视频队列是否有数据(video_packet_queue.size()==0)。若没有数据,则用pthread_cond_wait去等待线程被唤醒。若队列有数据则唤醒的此线程,则直接从队列取出数据。这里取出数据分两步:第一步,先把队列移动到最前面video_packet_queue.front()。第二步,video_packet_queue.pop出队并删除数据。

3.4. getVideoQueueSize的讲解:

getVideoQueueSize主要是获取当前队列的长度,获取长度的步骤跟上面也差不多。

首先,pthread_mutex_lock加锁,然后通过count = video_packet_queue.size(),获取队列的数量。然后pthread_mutex_unlock解锁。


http://www.hkcw.cn/article/JsMegvuACP.shtml

相关文章

使用Process Explorer、System Informer(Process Hacker)和Windbg工具排查软件高CPU占用问题

目录 1、问题现象 2、使用Process Explorer和System Informer&#xff08;该工具原先叫Process Hacker&#xff09;查看占用CPU高的线程 3、使用System Informer工具时发现了一个关键细节 4、将Windbg附加到软件进程上&#xff0c;根据System Informer中显示的线程id到Wind…

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…

传统业务对接AI-AI编程框架-Rasa的业务应用实战(1)--项目背景即学习初衷

我的初衷&#xff1a;我想学习AI。具体的方向是这样的&#xff1a;原本传统的平台业务去对接智能体。比如发票业务&#xff0c;发票的开具、审核、计税、回款等。根据用户在业务系统前台界面输入若干提示词 或者 语音输入简短语音信息&#xff0c;可以通过智能体给出需要处理的…

【八股消消乐】索引失效与优化方法总结

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本专栏《八股消消乐》旨在记录个人所背的八股文&#xff0c;包括Java/Go开发、Vue开发、系统架构、大模型开发、具身智能、机器学习、深度学习、力扣算法等相关知识点&#xff…

Java面试八股--06-Linux篇

目录 一、Git 1、工作中git开发使用流程&#xff08;命令版本描述&#xff09; 2.Reset与Rebase&#xff0c;Pull与Fetch的区别 3、git merge和git rebase的区别 4、git如何解决代码冲突 5、项目开发时git分支情况 二、Linux 1、Linux常用的命令 2、如何查看测试项目的…

动态规划-647.回文子串-力扣(LeetCode)

一、题目解析 这里的子字符串是连续的&#xff0c;与之前的子序列不同&#xff0c;这里需要我们统计回文子串的数目。 二、算法原理 这里也有其他算法可以解决该问题&#xff0c;如中心扩展算法 时间复杂度O(N^2)/空间复杂度O(1)&#xff0c;马拉车算法(具有局限性) 时间复杂…

条形进度条

组件 <template><view class"pk-detail-con"><i class"lightning" :style"{ left: line % }"></i><i class"acimgs" :style"{ left: line % }"></i><view class"progress&quo…

大模型赋能:金融智能革命中的特征工程新纪元

一、AI进化论&#xff1a;从“判别”到“生成”的金融新战场 1.1 判别式AI的“痛点”与大模型的“破局” 想象这样一幅画面&#xff1a;银行风控模型像老式收音机&#xff0c;需要人工反复调试参数才能捕捉风险信号&#xff1b;而大模型则是智能调音台&#xff0c;能自动“听…

HA: Wordy靶场

HA: Wordy 来自 <HA: Wordy ~ VulnHub> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.128&#xff0c;靶场IP192.168.23.130 3&#xff0c;对靶机进行端口服务探…

技巧小结:外部总线访问FPGA寄存器

概述 需求&#xff1a;stm32的fsmc总线挂载fpga&#xff0c;stm32需要访问fpga内部寄存器 1、分散加载文件将变量存放到指定地址即FPGA寄存器地址 sct文件指定变量存储地址&#xff0c;从而可以直接访问外设&#xff0c;&#xff08;28335也可以&#xff0c;不过用的是cmd文件…

深入理解 x86 汇编中的重复前缀:REP、REPZ/REPE、REPNZ/REPNE(进阶详解版)

一、重复前缀&#xff1a;串操作的 “循环加速器” 如果你写过汇编代码&#xff0c;一定遇到过需要重复处理大量数据的场景&#xff1a; 复制 1000 字节的内存块比较两个长达 200 字符的字符串在缓冲区中搜索特定的特征值 手动用loop指令编写循环&#xff1f;代码冗长不说&a…

【PCB设计】STM32开发板——原理图设计(电源部分)

一、PCB设计流程 二、准备工作 1.点击文件新建工程并命名 2.新建图页 在绘制较为复杂的原理图时&#xff0c;可以建立多个图页&#xff0c;使得原理图更加清晰。 右击原理图→新建图页 右击→重命名 3.设计规则相关配置 取消勾选第22个 4.调整页面大小 5.放置“电源树”图片…

C++仿RabbitMQ实现消息队列

前言 本项目将使用 C 在 Linux&#xff08;CentOS 7.6&#xff09; 环境下开发一个仿 RabbitMQ 的简易消息队列。 开发和调试环境如下&#xff1a; 操作系统&#xff1a;Linux (CentOS 7.6) 编辑器&#xff1a;Visual Studio Code / Vim 编译器&#xff1a;g&#xff08;GNU…

离散数学_数理逻辑(二):命题逻辑的推理

前言 每一件事都存在现象和本质.现象是表面,本质是内在.数学可以说是自然科学之母,是一切自然现象的本质.对于编程,表面上是在写代码,实际上是在用离散数学理解问题和解决问题. 引入 命题逻辑的推理部分. "推理"在思考中占了很大比重.笔者曾经把学习方法分了两种:一…

KITTI数据集(计算机视觉和自动驾驶领域)

KITTI&#xff08;Karlsruhe Institute of Technology and Toyota Technological Institute at Chicago&#xff09;数据集是计算机视觉和自动驾驶领域中最广泛使用的基准数据集之一。它由德国卡尔斯鲁厄理工学院和美国芝加哥丰田技术研究所联合发布&#xff0c;旨在推动自动驾…

力扣4.寻找两个正序数组的中位数

文章目录 题目介绍题解 题目介绍 题解 题解链接&#xff1a;题解 核心思路&#xff1a;通过二分查找的确定分割点使左右两部分元素数量相等。 class Solution {public double findMedianSortedArrays(int[] nums1, int[] nums2) {int n1 nums1.length;int n2 nums2.length…

Windows下将Nginx设置注册安装为服务方法!

一、需求背景 每次启动 Nginx 都要去到 Nginx 安装目录下寻找 nginx.exe 文件点击&#xff0c;很是麻烦。 并且远程登录桌面&#xff0c;有时注销用户&#xff0c;会把在当前用户打开的nginx关闭了。 于是考虑可不可以跟其它服务一样能够开机自启&#xff1f;显然是可以的。…

web第九次课后作业--SpringBoot基于mybatis实现对数据库的操作

前言 在前面我们学习MySQL数据库时&#xff0c;都是利用图形化客户端工具(如&#xff1a;idea、datagrip)&#xff0c;来操作数据库的。 在客户端工具中&#xff0c;编写增删改查的SQL语句&#xff0c;发给MySQL数据库管理系统&#xff0c;由数据库管理系统执行SQL语句并返回执…

SpringBoot+XXL-JOB:高效定时任务管理

一、前言 在现代应用程序中&#xff0c;定时任务是不可或缺的一部分。Spring Boot 和 XXL-Job 为你提供了一个强大的工具组合&#xff0c;以简化任务调度和管理。本文将带领你探索如何将这两者集成在一起&#xff0c;实现高效的定时任务管理。无论你是初学者还是有经验的开发者…

java-spring

入门案例 通过bean创建对象 先通过spring的ClassPathXmlApplicationContext读取xml文件 ,然后通过getbean()函数获取对象&#xff0c;进行操作通过反射机制&#xff0c;吸纳Class的函数forName(class属性)创建对象&#xff0c;然后clazz.getDeclaredConstructor().newinstanc…