首先感谢下这个博主 我很多都是在他这边借鉴的,下面是他的文章的原链接
https://blog.csdn.net/qq_38318941/article/details/102558351
下面是我对他的线程方面的改动 以及我的一些理解,我才用的是官方推荐的moveToThread的方法来创建多线程的。废话不多说,开始讲解关于生产者消费者模型的搭建。
QT中的生产者消费者模型涉及到很多知识,其中生产者和消费者涉及到多线程问题,还有由于生产者消费者要操作同一块内存的数据所以,这又涉及到队列(QQueue)和信号量(QSemaphore)的综合应用.
这里对需要进行同一块操作的内存进行包装成一个类blockMsgQueue
blockMsgQueue.h文件
#ifndef BLOCKMSGQUEUE_H
#define BLOCKMSGQUEUE_H
#include <QSemaphore>
#include <QMutex>
#include <QQueue>
class blockMsgQueue
{
public:
blockMsgQueue(const int &maxMsgsNum, const unsigned int &msgSize);
~blockMsgQueue();
void addMsg(const char *msgPack);
void getMsg(char *msgPack);
private:
int m_maxMsgsNum;
unsigned int m_msgSize;
QSemaphore *m_pFreeMsgs;
QSemaphore *m_pUsedMsgs;
QQueue<char *> m_queue;
QMutex m_mutex;
};
#endif // BLOCKMSGQUEUE_H
blockMsgQueue.c文件
#include "blockMsgQueue.h"
blockmsgqueue::blockMsgQueue(const int &m_maxMsgsNum, const unsigned int &msgSize)
:m_maxMsgsNum(m_maxMsgsNum),
m_msgSize(msgSize)
{
m_pFreeMsgs = new QSemaphore(m_maxMsgsNum);
m_pUsedMsgs = new QSemaphore(0);
}
blockmsgqueue::~blockmsgqueue()
{
}
void blockmsgqueue::addMsg(const char *msgPack)
{
m_pFreeMsgs->acquire(1);
m_mutex.lock();
char *msgIn = new char[m_msgSize];
memcpy(msgIn, msgPack, m_msgSize);
m_queue.enqueue(msgIn);
m_mutex.unlock();
m_pUsedMsgs->release(1);
}
void blockmsgqueue::getMsg(char *msgPack)
{
m_pUsedMsgs->acquire(1);
m_mutex.lock();
char *msgOut = m_queue.dequeue();
memcpy(msgPack, msgOut, m_msgSize);
m_mutex.unlock();
m_pFreeMsgs->release(1);
}
对这个类的解释:
m_maxMsgsNum:最大的队列数量就是可以操作内存块的块数。
m_msgSize:每小块内存的尺寸。
信号量:
QSemaphore(n):建立对象时可以给n个资源,就是给多少块内存。
void acquire(n):这个函数,操作一次就减少n个资源,如果现在资源不到n个就会阻塞(在这个项目中如果没有一个资源就阻塞等待能有可用的资源)。
void release(n):这个函数,操作一次就增加n个资源。
在操作同一块内存块组,需要两个信号量来配合使用,一个是空闲内存块的信号量m_pFreeMsgs,用来标识是否有可用的内存块,这个是给生产者使用的。另一个是已经使用了多少内存块的信号量m_pUsedMsgs,用来标识是否有转载有用户数据的内存块,这个是给消费者使用的。
m_pFreeMsgs = new QSemaphore(m_maxMsgsNum);
m_pUsedMsgs = new QSemaphore(0);
这里是预先设定好信号量,预示着有10个空的内存块,0个装载用户数据的内存块
队列:
队列是一种数据结构,一种先入先出的数据结构
enqueue:入队
dequeue:出队
这个函数要将数据装载在共享内存块组内
void blockmsgqueue::addMsg(const char *msgPack)
{
m_pFreeMsgs->acquire(1);//用掉一个内存块,在下面要装载数据了
m_mutex.lock();//因为要操作同一块内存,就要锁住防止数据出问题
char *msgIn = new char[m_msgSize];