QT学习笔记18(多线程互斥量、信号量)

一、互斥量

为了防止多个线程对同一个资源进行访问,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();
}

 

 

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值