QSemaphore的使用

QSemaphore介绍

QSemaphore 是 Qt 框架中提供的一个用于多个线程同步和数据存取的信号量类。与互斥锁(QMutex)和条件变量(QWaitCondition)一样,QSemaphore 也是一个跨平台通用的同步机制。

QSemaphore 类提供了一种通用计数信号量。信号量是互斥锁的一种泛化应用,与互斥锁不同的是,信号量可以被多次获取。信号量通常用于保护一定数量的相同资源,而且这些资源可以被多个线程共享

QSemaphore 更加灵活,它并不需要像互斥锁那样使用 lock() 和 unlock()、tryLock() 等方法来实现加锁解锁操作。QSemaphore 主要通过其 count() 方法控制在某时刻同时运行的等待线程数量和可执行的线程数量,可以用来实现资源池管理、限流等功能。

QSemaphore(int n = 0)中的n,是指允许访问被保护资源的最大并发线程数。QSemaphore 类中的信号量实际上是一个计数器,它用于记录能够同时访问某个共享资源的线程数。在 QSemaphore 中使用 acquire() 函数获取该信号量时,计数器会减 1;当使用 release() 函数释放该信号量时,计数器会加 1。因此,如果将 size 指定为 n,则表示在任何时刻,最多允许有 n 个线程同时访问被保护资源。

下面是官方的例子:

  QSemaphore sem(5);      // sem.available() == 5

  sem.acquire(3);         // sem.available() == 2
  sem.acquire(2);         // sem.available() == 0
  sem.release(5);         // sem.available() == 5
  sem.release(5);         // sem.available() == 10

  sem.tryAcquire(1);      // sem.available() == 9, returns true
  sem.tryAcquire(250);    // sem.available() == 9, returns false

QSemaphore代码示例

下面代码定义了生产者和消费者两类线程,模拟了一个资源池管理的场景。在生产者线程中通过 releaseResource() 方法放入共享资源,而在消费者线程中通过 getResource() 方法获取它们。为了防止多个线程同时访问同一份资源,我们使用了互斥锁(QMutex)进行加锁解锁操作,并结合信号量(QSemaphore)进行资源数量的限制,从而确保了程序可以安全地并发运行。

pool.h

#ifndef POOL_H
#define POOL_H

#include <QObject>
#include <QtCore/QThread>
#include <QtCore/QSemaphore>
#include <QtCore/QDebug>
#include <QMutex>

class Pool : public QObject
{
    Q_OBJECT
public:
    Pool(int size):m_size(size) {
           m_resourcesAvailable = new QSemaphore(size); //size是初始资源数量
       }

    void getResource() {
        m_resourcesAvailable->acquire(); // 请求获取信号量 , 阻塞直到有可用的资源
        qDebug() << "getResource current thread id : " << QThread::currentThreadId();
        m_mutex.lock(); // 加锁
        QString resource = m_resources.takeFirst();
        m_mutex.unlock(); // 解锁
        qDebug() << "getResource get resource : " << resource;
    }

    void releaseResource(QString res) {
       m_mutex.lock(); // 加锁
       m_resources.append(res);
       m_mutex.unlock(); // 解锁
       m_resourcesAvailable->release(); // 释放信号量,资源数+1
       qDebug() << "releaseResource current thread id : "<< QThread::currentThreadId() << ", Remaining num :" << m_resourcesAvailable->available();
    }

private:
    QList<QString> m_resources{"ResourceA", "ResourceB", "ResourceC", "ResourceD", "ResourceE"};
    int m_size;
    QMutex m_mutex; // QMutex 提供资源独占的能力。
    QSemaphore *m_resourcesAvailable; // 信号量,可用资源数量
};

#endif // POOL_H

threadmanager.h

#ifndef THREADMANAGER_H
#define THREADMANAGER_H

#include <QtCore/QThread>
#include <QtCore/QSemaphore>
#include <QtCore/QDebug>
#include <QMutex>
#include "pool.h"

class Consumer : public QThread {
    Q_OBJECT
public:
    Consumer(Pool *pool) : m_pool(pool) {}

    ~Consumer() override {}

    void run() override {
        for (int i = 0; i < 3; ++i) {
            qDebug() << "Consuming at" << QThread::currentThreadId();
            m_pool->getResource();
            msleep(500);
        }
    }

private:
    Pool *m_pool;
};

class Producer : public QThread {
    Q_OBJECT
public:
    Producer(Pool *pool, QString resource) : m_pool(pool), m_resource(resource) {}

    ~Producer() override {}

    void run() override {
        for (int i = 0; i < 2; ++i) {
            qDebug() << "Producing at" << QThread::currentThreadId();
            m_pool->releaseResource(m_resource.arg(i));
            msleep(1000);
        }
    }

private:
    Pool *m_pool;
    QString m_resource;
};

#endif // THREADMANAGER_H

main.cpp

#include <QCoreApplication>
#include "pool.h"
#include "threadmanager.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Pool pool(5); // 共享资源池
    Consumer consumer1(&pool), consumer2(&pool), consumer3(&pool);
    Producer producer1(&pool, "Producer1 Resource %1"), producer2(&pool, "Producer2 Resource %1");

    producer1.start();
    producer2.start();
    consumer1.start();
    consumer2.start();
    consumer3.start();


    consumer1.wait();
    consumer2.wait();
    consumer3.wait();
    producer1.wait();
    producer2.wait();

    return a.exec();
}

运行结果:

Producing at 0x7f373f062700
releaseResource current thread id :  0x7f373f062700 , Remaining num : 6
Producing at 0x7f373e861700
releaseResource current thread id :  0x7f373e861700 , Remaining num : 7
Consuming at 0x7f373e060700
getResource current thread id :  0x7f373e060700
getResource get resource :  "ResourceA"
Consuming at 0x7f373d85f700
getResource current thread id :  0x7f373d85f700
getResource get resource :  "ResourceB"
Consuming at 0x7f373d05e700
getResource current thread id :  0x7f373d05e700
getResource get resource :  "ResourceC"
Consuming at 0x7f373d05e700
getResource current thread id :  0x7f373d05e700
getResource get resource :  "ResourceD"
Consuming at 0x7f373d85f700
getResource current thread id :  0x7f373d85f700
getResource get resource :  "ResourceE"
Consuming at 0x7f373e060700
getResource current thread id :  0x7f373e060700
getResource get resource :  "Producer1 Resource 0"
Producing at 0x7f373e861700
releaseResource current thread id :  0x7f373e861700 , Remaining num : 2
Producing at 0x7f373f062700
releaseResource current thread id :  0x7f373f062700 , Remaining num : 3
Consuming at 0x7f373e060700
getResource current thread id :  0x7f373e060700
getResource get resource :  "Producer2 Resource 0"
Consuming at 0x7f373d85f700
getResource current thread id :  0x7f373d85f700
getResource get resource :  "Producer2 Resource 1"
Consuming at 0x7f373d05e700
getResource current thread id :  0x7f373d05e700
getResource get resource :  "Producer1 Resource 1"

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zw_ggr_2017

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值