项目1:队列的讲解(下):C++多线程队列使用
一.多线程队列的框图:
该图展示了典型的多线程队列操作流程。系统需要创建两个独立线程:一个负责入队操作,另一个负责出队操作。入队线程通过调用push API将数据添加到队列尾部,并在每次插入操作后通过pthread_cond_broadcast发出唤醒信号。与此同时,出队线程处于等待状态(pthread_cond_wait),一旦收到入队线程的唤醒通知,便会立即执行数据出队操作。
二.Linux多线程的基本API:
2.1. pthread_mutex_lock:
int pthread_mutex_lock(pthread_mutex_t *mutex);
第一个传入参数:pthread_mutex_t结构体指针
功能:这个是互斥锁加锁功能,就是每次线程调用的时候都会把锁加上,使其保证访问数据的原子性,直到解锁为止。
2.2. pthread_mutex_unlock:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
第一个传入参数:pthread_mutex_t结构体指针
功能:这个是互斥锁解锁功能,就是每次线程访问完资源的时候都会把锁解锁。
2.3. pthread_cond_broadcast:
int pthread_cond_broadcast(pthread_cond_t *cond);
传入参数:pthread_cond_t的结构体指针
功能:唤醒所有正在pthread_cond_wait(线程等待)的线程
2.4. pthread_cond_wait:
int pthread_cond_wait (pthread_cond_t *__restrict __cond , pthread_mutex_t *__restrict __mutex)
第一个参数:pthread_cond_t的结构体指针
第二个参数:pthread_mutex_t结构体指针
功能:线程等待并挂起,若被唤醒了,则直接跳出挂起状态。
三.推流项目中视频队列的实现:
#include "ffmpeg_video_queue.h"//VIDEO队列的构造器,包含mutex的初始化和条件变量初始化
VIDEO_QUEUE::VIDEO_QUEUE()
{pthread_mutex_init(&videoMutex, NULL);//mutex的初始化pthread_cond_init(&videoCond, NULL);//条件变量初始化
}//VIDEO队列的析构函数,锁的销毁和条件变量的销毁
VIDEO_QUEUE ::~VIDEO_QUEUE()
{pthread_mutex_destroy(&videoMutex);//锁的销毁pthread_cond_destroy(&videoCond);//条件变量的销毁
}//VIDEO_QUEUE的插入视频队列操作
int VIDEO_QUEUE::putVideoPacketQueue(video_data_packet_t *video_packet)
{pthread_mutex_lock(&videoMutex); //上视频锁video_packet_queue.push(video_packet);//向视频队列插入video_data_packet_t包pthread_cond_broadcast(&videoCond);//唤醒视频队列pthread_mutex_unlock(&videoMutex);//解视频锁return 0;
}//VIDEO_QUEUE取出视频包
video_data_packet_t *VIDEO_QUEUE::getVideoPacketQueue()
{pthread_mutex_lock(&videoMutex);//上视频锁while (video_packet_queue.size() == 0){pthread_cond_wait(&videoCond, &videoMutex); //当视频队列没有数据的时候,等待被唤醒}video_data_packet_t *item = video_packet_queue.front();//把视频数据包移到最前面video_packet_queue.pop();//pop取出视频数据并删除pthread_mutex_unlock(&videoMutex);//解视频锁return item;
}//VIDEO_QUEUE视频队列长度
int VIDEO_QUEUE::getVideoQueueSize()
{unsigned int count = 0;pthread_mutex_lock(&videoMutex);//上视频锁count = video_packet_queue.size();//获取视频队列长度pthread_mutex_unlock(&videoMutex);//解视频锁return count;
}
该示意图展示了视频队列的实现流程。VIDEO_QUEUE类封装了三个核心方法:putVideoPacketQueue用于添加视频队列数据,getVideoPacketQueue用于获取队列数据,getVideoQueueSize则用于查询当前队列长度。
3.1. VIDEO_QUEUE构造器:
这里创建一个VIDEO_QUEUE的C++的构造器,C++构造器主要初始化了线程的量。包括:线程锁的初始化(pthread_mutex_init)、线程条件变量的初始化(pthread_cond_init)。
3.2.putVideoPacketQueue的讲解:
//VIDEO_QUEUE的插入视频队列操作
int VIDEO_QUEUE::putVideoPacketQueue(video_data_packet_t *video_packet)
{pthread_mutex_lock(&videoMutex); //上视频锁video_packet_queue.push(video_packet);//向视频队列插入video_data_packet_t包pthread_cond_broadcast(&videoCond);//唤醒视频队列pthread_mutex_unlock(&videoMutex);//解视频锁return 0;
}
putVideoPacketQueue
主要用于处理video_data_packet_t
的入队操作。具体流程如下:
- 首先通过
pthread_mutex_lock
获取互斥锁; - 执行入队操作
video_packet_queue.push(video_packet)
; - 入队完成后,通过
pthread_cond_broadcast
通知出队线程处理数据; - 最后调用
pthread_mutex_unlock
释放锁。
之前相关联系代码截图
3.3. getVideoPacketQueue的讲解:
//VIDEO_QUEUE取出视频包
video_data_packet_t *VIDEO_QUEUE::getVideoPacketQueue()
{pthread_mutex_lock(&videoMutex);//上视频锁while (video_packet_queue.size() == 0){pthread_cond_wait(&videoCond, &videoMutex); //当视频队列没有数据的时候,等待被唤醒}video_data_packet_t *item = video_packet_queue.front();//把视频数据包移到最前面video_packet_queue.pop();//pop取出视频数据并删除pthread_mutex_unlock(&videoMutex);//解视频锁return item;
}
getVideoPacketQueue
主要负责处理 video_data_packet_t
的入队操作,具体流程如下:
- 首先通过
pthread_mutex_lock
进行加锁操作 - 检查视频队列是否为空(
video_packet_queue.size()==0
)- 如果队列为空,则调用
pthread_cond_wait
等待线程被唤醒 - 如果队列不为空且线程已被唤醒,则执行数据出队操作
- 如果队列为空,则调用
- 数据出队分为两个步骤:
- 使用
video_packet_queue.front()
获取队列首部数据 - 调用
video_packet_queue.pop()
移除队列首部数据
- 使用
之前相关联系代码截图