一、互斥量
为了防止多个线程对同一个资源进行访问,Qt中加入互斥量,互斥量可以通过QMutex或者QMutexLocker类来实现。
1、QMutex类
QMutex类对互斥量的处理,它被用来保护一段临界区代码,即每次只允许一个线程访问这段代码而不能被其他线程随意调用。
QMutex类还提供了一个tryLock()函数,如果互斥量已被锁定,则立即返回。
#include <QMutex>
QMutex qMutex;
//线程槽函数
void WorkThread::startThreadSlot()
{
qMutex.tryLock();
while(true)
{
if(isStop)
return;
for(int n=0;n<10;n++)
qDebug()<<n<<n<<n<<n<<n<<n<<n<<n;
QThread::sleep(1);
}
qMutex.unlock();
}
2、QMutexLocker类
QMutexLocker这个类是基于QMutex的便利类,这个类不能够定义私有成员变量 和 全局变量,只能够定义局部变量来使用。
- Qt提供的QMutexLocker类可以简化互斥量的处理,它在构造函数中接收一个QMutex对象作为参数并将其锁住,在析构函数中解锁这个互斥量
- locker函数作为局部变量会在这个函数退出时结束其作用域,从而自动对互斥量mutex解锁。
优点:只需要一条语句,简化了编程的复杂程度。
使用方法:
(1)先定义一个QMutex类的变量
(2)在需要上锁的地方定义一个QMutexLocker类的变量
#include <QMutex>
QMutex qMutex;
//线程槽函数
void WorkThread::startThreadSlot()
{
QMutexLocker m_lock(&qMutex);
while(true)
{
if(isStop)
return;
for(int n=0;n<10;n++)
qDebug()<<n<<n<<n<<n<<n<<n<<n<<n;
QThread::sleep(1);
}
}
二、信号量
信号量可以理解为对互斥量功能的扩展,互斥量只能锁定一次而信号量可以获取多次,它可以用来保存一定数量的同种资源。
以下以生产者消费者模型举例:
#include <QCoreApplication>
#include <QSemaphore>
#include <QThread>
#include <stdio.h>
const int DataSize=1000;
const int BufferSize=80;
int buffer[BufferSize];//缓存数据
QSemaphore freeBytes(BufferSize);//freeBytes信号量控制可被生产者填充的缓冲部分
QSemaphore usedBytes(0);//usedBytes信号量控制可被消费者读取的缓冲区部分
class Producer : public QThread
{
public:
Producer();
void run();
};
Producer::Producer()
{
}
void Producer::run()
{
for(int i=0;i<DataSize;i++)
{
freeBytes.acquire();//生产者线程首先获取一个空闲单元,如果此时缓冲区培被消费者尚未读取的数据填满,对
//此函数的调用就会阻塞,直到消费者读取了这些数据为止
buffer[i%BufferSize]=(i%BufferSize);//一旦生成者获取了某个空闲单元,就使当前的缓存单元序号填写这个缓冲区单元
usedBytes.release();//调用该函数将可用资源加1,表示消费者此时可以读取这个刚刚填写的单元
}
}
//Consumer继承QThread类
class Consumer : public QThread
{
public:
Consumer();
void run();
};
Consumer::Consumer()
{
}
void Consumer::run()
{
for(int i=0;i<DataSize;i++)
{
usedBytes.acquire();//消费者线程首先获取一个可被读取的单元,如果缓冲区中没有包含任何可以读取的数据,对此函数的调用就会阻塞,直到生产者生产了一些数据为止
fprintf(stderr,"%d",buffer[i%BufferSize]);//一旦消费者读取了这个单元,会将这个单元的内容打印出来
if(i%16==0&&i!=0)
fprintf(stderr,"\n");
freeBytes.release();//调用该函数使得这个单元变为空闲,已被生产者下次填充
}
fprintf(stderr,"\n");
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Producer producer;
Consumer consumer;
producer.start();
consumer.start();
producer.wait();
consumer.wait();
return a.exec();
}