Qt的互斥量用法

目的

互斥量的概念

互斥量是一个可以处于两态之一的变量:解锁和加锁。这样,只需要一个二进制位表示它,不过实际上,常常使用一个整型量,0表示解锁,而其他所有的值则表示加锁。互斥量使用两个过程。当一个线程(或进程)需要访问临界区时,它调用mutex_lock。如果该互斥量当前是解锁的(即临界区可用),此调用成功,调用线程可以自由进入该临界区。

另一方面,如果该互斥量已经加锁,调用线程被阻塞,直到在临界区中的线程完成并调用mutex_unlock。如果多个线程被阻塞在该互斥量上,将随机选择一个线程并允许它获得锁。

QMutex的用法

QMutex各QMutexLocker是基于互斥量的线程同步类,QMutex定义的实例是一个互斥量,QMutex主要提供了3个函数。

lock:

锁定互斥量,如果另外一个线程锁定了这个互斥量,它将阻塞执行直到其它线程解锁这个互斥量。

unlock:

解锁一个互斥量,需要与lock()配对使用。

tryLock():

试图锁定一个互斥量,如果成功锁定就返回true,如果其它线程已经锁定了这一个互斥量,就返回false,但不阻塞程序执行。

QMutexLocker:

是另外一个简化的互斥量处理的类。QMutexLocker的构造函数接受一个互斥量作为参数,将其锁定,QMutexLocker的析构函数则将此互斥量解锁。

例子

下面通过实现,两个程序对数量进行累加,演示互斥量的用法:

业务类:

cpp 复制代码
#include "business.h"
#include <QDebug>
#include <QThread>
#include <QDateTime>
int Business::s_num = 0;
QMutex Business::s_mutex;
Business::Business(QObject *parent) : QObject(parent)
{
}
int Business::getNum()
{
    return s_num;
}
void Business::addNum()
{
    //qDebug()<<"enter function addNum currentThreadId=" << QThread::currentThreadId()
    //       <<" currentTime="<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    s_mutex.lock();
    s_num++;
    qDebug()<<"s_num="<<s_num;
    s_mutex.unlock();
    //qDebug()<<"exit function addNum currentThreadId=" << QThread::currentThreadId()
    //       <<" currentTime="<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
}
int Business::slot_getNum()
{
    return this->getNum();
}
void Business::slot_addNum()
{
    this->addNum();
}

线程类

cpp 复制代码
#include "businessInThread.h"
BusinessInThread::BusinessInThread(QObject *parent) : QObject(parent)
{
    m_pWorkerThread = new QThread();
    m_pBusiness = new Business();
    m_pBusiness->moveToThread(m_pWorkerThread);
    connect(m_pWorkerThread, &QThread::finished, m_pBusiness, &QObject::deleteLater);
    connect(this, &BusinessInThread::signal_getNum, m_pBusiness,
            &Business::slot_getNum, Qt::BlockingQueuedConnection);
    connect(this, &BusinessInThread::signal_addNum, m_pBusiness, &Business::slot_addNum);
    m_pWorkerThread->start();
}
BusinessInThread::~BusinessInThread()
{
    m_pWorkerThread->quit();
    m_pWorkerThread->wait();
}
int BusinessInThread::getNum()
{
    return signal_getNum();
}
void BusinessInThread::addNum()
{
     signal_addNum();
}

主程序

cpp 复制代码
#include <QCoreApplication>
#include "businessInThread.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    BusinessInThread businessInThread1;
    BusinessInThread businessInThread2;
    for(int i = 0; i < 5; i++)
    {
       businessInThread1.addNum();
       businessInThread2.addNum();
    }
    return a.exec();
}

运行结果:

如果去掉锁的话,就会这样:

QMutextLocker的简化用法

这个函数:

cpp 复制代码
void Business::addNum()
{
    //qDebug()<<"enter function addNum currentThreadId=" << QThread::currentThreadId()
    //       <<" currentTime="<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    s_mutex.lock();
    s_num++;
    qDebug()<<"s_num="<<s_num;
    s_mutex.unlock();
    //qDebug()<<"exit function addNum currentThreadId=" << QThread::currentThreadId()
    //       <<" currentTime="<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
}

可以简化为:

cpp 复制代码
void Business::addNum()
{
    //qDebug()<<"enter function addNum currentThreadId=" << QThread::currentThreadId()
    //       <<" currentTime="<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    //s_mutex.lock();
    QMutexLocker Locker(&s_mutex);
    s_num++;
    qDebug()<<"s_num="<<s_num;
    //s_mutex.unlock();
    //qDebug()<<"exit function addNum currentThreadId=" << QThread::currentThreadId()
    //       <<" currentTime="<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
}

总结

互斥锁,就是只有锁定与解锁,两种状态,可以说,是最简单的锁,也是最实用的锁。

相关推荐
死磕音视频7 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
顽疲9 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
用户8334423966149 小时前
从批量操作到任务中心,再到现场工作台:DeviceForge v2.10—v2.12 完整演进
qt
Wang's Blog9 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友
宛 禾11 小时前
Qt 控件入门:QLabel 从拖拽到对象树,一篇讲透
c++·qt·学习
程序喵大人11 小时前
【C++入门】编译链接模型 - 07 链接器怎样把符号对上号
开发语言·c++·编译器·编译链接·链接器
微三云 - 廖会灵 (私域系统开发)11 小时前
供应链系统实战:多渠道订单聚合与分布式库存一致性方案总结
开发语言·分布式·php
学逆向的12 小时前
C 数据溢出与精度丢失
c语言·开发语言·网络安全
霸道流氓气质12 小时前
AgentFlow 入门与实战:Task-Based 并发、EWMA 动态调度与四道门禁的 Java 生产级编排
java·开发语言
释厄62313 小时前
错误无误公理——错误正确本同源都迭代定律——逆转有价值
android·开发语言·kotlin