Qt编程技巧总结篇(5)-信号-槽-多线程(四)
多线程学习,使用QSemaphore
提供线程同步方法, 信号量(Semaphore)是一种限制对共享资源进行访问的线程同步机制。与互斥量的区别是,信号量可以多次使用,而互斥量只能被锁定一次。 信号量常用来保护一定数量的相同资源,如数据采集时的双缓冲区。OK,开整~
QSemaphore提供的函数
acquire(int n)
尝试获得n个资源,如果没有阻塞到有n个资源;release(int n)
释放n个资源,信号资源全部可用后再release;int available()
返回当前信号量可用的资源个数;bool tryAcquire(int n=1)
尝试获取n个资源,不成功时不阻塞线程。
实例与应用
下面的例子是《 QT5.9 c++ 开发指南》中的例子,代码放这里,欢迎参考学习!
qmythread.h 文件中定义了两个线程,其中QThreadDAQ
线程负责将采集的数据放入缓冲区,QThreadShow
线程负责读取缓冲区的数据并显示。很有趣的交互方式,两个缓冲区进行读写操作,又称双缓冲读取方式。
#ifndef QMYTHREAD_H
#define QMYTHREAD_H
//#include <QObject>
#include <QThread>
class QThreadDAQ : public QThread
{
Q_OBJECT
private:
bool m_stop=false; //停止线程
protected:
void run() Q_DECL_OVERRIDE;
public:
QThreadDAQ();
void stopThread();
};
class QThreadShow : public QThread
{
Q_OBJECT
private:
bool m_stop=false; //停止线程
protected:
void run() Q_DECL_OVERRIDE;
public:
QThreadShow();
void stopThread();
signals:
void newValue(int *data,int count, int seq);
};
#endif // QMYTHREAD_H
qmythread.cpp 文件中重写两个线程的run()函数
#include "qmythread.h"
#include <QSemaphore>
const int BufferSize = 8;
int buffer1[BufferSize];
int buffer2[BufferSize];
int curBuf=1; //当前正在写入的Buffer
int bufNo=0; //采集的缓冲区序号
quint8 counter=0;//数据生成器
/* ***
* 信号量(Semaphore)是一种限制对共享资源进行访问的线程同步机制。
* 与互斥量的区别是,信号量可以多次使用,而互斥量只能被锁定一次。
* 信号量常用来保护一定数量的相同资源,如数据采集时的双缓冲区。
* 几个函数:
* acquire(int n) 尝试获得n个资源,如果没有阻塞到有n个资源;
* release(int n) 释放n个资源,信号资源全部可用后再release;
* int available() 返回当前信号量可用的资源个数;
* bool tryAcquire(int n=1) 尝试获取n个资源,不成功时不阻塞线程。
*/
QSemaphore emptyBufs(2);//信号量:空的缓冲区个数,初始资源个数为2
QSemaphore fullBufs; //满的缓冲区个数,初始资源为0
QThreadDAQ::QThreadDAQ()
{
}
void QThreadDAQ::stopThread()
{
m_stop=true;
}
void QThreadDAQ::run()
{
m_stop=false;//启动线程时令m_stop=false
bufNo=0;//缓冲区序号
curBuf=1; //当前写入使用的缓冲区
counter=0;//数据生成器
int n=emptyBufs.available();
if (n<2) //保证 线程启动时emptyBufs.available==2
emptyBufs.release(2-n);
while(!m_stop)//循环主体
{
emptyBufs.acquire();//获取一个空的缓冲区
for(int i=0;i<BufferSize;i++) //产生一个缓冲区的数据
{
if (curBuf==1)
buffer1[i]=counter; //向缓冲区写入数据
else
buffer2[i]=counter;
counter++; //模拟数据采集卡产生数据
msleep(50); //每50ms产生一个数
}
bufNo++;//缓冲区序号
if (curBuf==1) // 切换当前写入缓冲区
curBuf=2;
else
curBuf=1;
fullBufs.release(); //有了一个满的缓冲区,available==1
}
quit();
}
void QThreadShow::run()
{
m_stop=false;//启动线程时令m_stop=false0
int n=fullBufs.available();
if (n>0)
fullBufs.acquire(n); //将fullBufs可用资源个数初始化为0
while(!m_stop)//循环主体
{
fullBufs.acquire(); //等待有缓冲区满,当fullBufs.available==0阻塞
int bufferData[BufferSize];
int seq=bufNo;
if(curBuf==1) //当前在写入的缓冲区是1,那么满的缓冲区是2
for (int i=0;i<BufferSize;i++)
bufferData[i]=buffer2[i]; //快速拷贝缓冲区数据
else
for (int i=0;i<BufferSize;i++)
bufferData[i]=buffer1[i];
emptyBufs.release();//释放一个空缓冲区
emit newValue(bufferData,BufferSize,seq);//给主线程传递数据
}
quit();
}
QThreadShow::QThreadShow()
{
}
void QThreadShow::stopThread()
{
m_stop=true;
}
小结
多线程的学习就更新到这里了,实现多线程的方式在这几篇文章中主要是 QMutex
、QWaitCondition
以及QSemaphore
这几种方式,灵活运用,多写多练,前路未卜,仍需奋力前行!加油,共勉。