1、QSemaphore(信号量):针对“资源 >1个”的情况。
1.1
QMutex:只保护一个资源。
信号量:通常用于保护“一定数量”的相同资源。
前面的几种锁都是用来保护“只有一个变量”的互斥量的。可是还有些互斥量(资源)的数量并不止一个,好比一个电脑安装了2个打印机,我已经申请了一个,可是我不能霸占这两个,你来访问的时候若是发现还有空闲的仍然能够申请到的。
因而这个互斥量能够分为2部分,已使用和未使用。一个线程在申请的时候,会对未使用到的部分进行加锁操做,若是加锁失败则阻塞。若是加锁成功,即又有一个资源被使用了,因而则将已使用到的部分解锁一个。
1.2
比如信号量的一个典型应用:同步生产者和消费者之间对循环缓冲区的访问;
以著名的生产者消费者问题为例,分析问题:生产者须要的是空闲位置存放产品,结果是可取的产品多了一个。因而,咱们能够定义2个信号量:QSemaphore freeSpace(给生产者使用)和 QSemaphore usedSpace(给消费者使用)。
1.3
1.4 相关成员函数
1.5 示例
const int BufferSize = 8;
//这2个buf,就是要进行保护管理的资源
int buffer1[BufferSize];//
int buffer2[BufferSize];//
int curBuf=1; //当前正在写入的Buffer
int bufNo=0; //采集的缓冲区序号
quint8 counter=0;//数据生成器
QSemaphore emptyBufs(2);//信号量:空的缓冲区个数,初始资源个数为2
QSemaphore fullBufs; //满的缓冲区个数,初始资源为0
//采用双缓冲方式:进行模拟数据采集。buffer1、buffer2
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)//循环主体
{
//============步骤2:=============//
//1.使用信号量emptyBufs获取一个资源:即获取一个空的缓冲区。emptyBufs--; 少一个
emptyBufs.acquire();
//2.每隔50ms,使counter值加1,然后写入当前正在写入的缓冲区。
//写入哪个缓冲区由curBuf决定。
//counter:是模拟采集的数据。连续增加:可以判断采集的数据是否连续
for(int i=0;i< BufferSize;i++) //产生一个缓冲区的数据
{
if (curBuf==1)
buffer1[i]=counter; //向缓冲区写入数据
else
buffer2[i]=counter;
counter++; //模拟数据采集卡产生数据
msleep(50); //每50ms产生一个数
}
//3.完成for循环后,正好写满一个缓冲区buffer。这时改变curBuf的值,切换用于写入的缓冲区
bufNo++;//缓冲区序号
if (curBuf==1) // 切换当前写入缓冲区
curBuf=2;
else
curBuf=1;
//============步骤3:=============//
//4.写满一个缓冲区后,使用信号量fullBufs释放一个资源。这时fullsBufs.available==1,表示有一个缓冲区被写满了
//这样,QThreadShow线程里使用fullBufs.acquire()就可以获得一个资源,可以读取已写满的缓冲区里的数据。
fullBufs.release(); //有了一个满的缓冲区,available==1
}
quit();//退出线程
}
void QThreadShow::run() //消费者线程
{
m_stop=false;//启动线程时令m_stop=false
int n=fullBufs.available();//可用资源
if (n>0)
fullBufs.acquire(n); //将fullBufs可用资源个数初始化为0(获取n个资源后,就剩0个了!相当于初始化为0个)
while(!m_stop)//循环主体
{
//============步骤1:=============//
//1.监测是否有已经写满数据的缓冲区
//以阻塞方式获取一个资源。只有当QThreadDAQ线程里写满一个缓冲区,执行一次fullBufs.release()后,
//fullBufs.acquire()才能获得资源并执行后面的代码。
fullBufs.acquire(); //fullBufs.available==0阻塞,等待有缓冲区满。
//============步骤4:=============//
int bufferData[BufferSize];
int seq=bufNo;
//2.立刻读取数据:用临时变量bufferData[BufferSize]将缓冲区里的数据读取出来
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];
//3.释放缓冲区,给QThreadDAQ线程用于写入
//释放一个空缓冲区。相当于emptyBufs++;多一个空缓冲区资源
emptyBufs.release();//给信号量emptyBufs释放一个资源
//4.发射信号newValue,给主线程dialog读取数据并显示
emit newValue(bufferData,BufferSize,seq);//给主线程传递数据
}
quit();
}
1.5.1 先启动“消费者线程”、2个线程全部使用terminate强制关闭
1.5.2
1.5.3