Qt中线程同步类介绍(一)

Qt中线程同步类介绍(一)

Qt中实现线程同步的类主要是:QMutex、QMutexLoker、QReadWriteLocker、QReadLocker、QWriteLocker、QSemaphore、QWaitCondition和QSemaphore。

一、基本概念

QMutex和QMutexLocker

QMutex 和QMutexLocker是基于互斥量的线程同步类。

(1)QMutex

主要提供一下3个函数:

lock():加锁。如果锁已经被其他线程占用,当前线程会阻塞(等待) 直到锁被释放;

unlock():解锁。必须和lock()成对调用,否则会导致死锁;

trylock():尝试加锁。如果锁被占用,不会阻塞,直接返回false;如果加锁成功返回true(适合不想阻塞的场景)。

QMutex简单使用示例:

c++ 复制代码
#include <QCoreApplication>
#include <QMutex>
#include <QThread>
#include <QDebug>

QMutex mutex; // 全局互斥锁
int sharedValue = 0; // 共享资源

void threadFunc()
{
    for (int i = 0; i < 5; ++i)
    {
        mutex.lock(); // 加锁:进入临界区
        sharedValue++; // 操作共享资源,此时只有当前线程能执行
        qDebug() << QThread::currentThreadId() << "sharedValue:" << sharedValue;
        mutex.unlock(); // 解锁:离开临界区,其他线程可加锁

        QThread::msleep(10); // 模拟耗时操作
    }
}

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

    // Set up code that uses the Qt event loop here.
    // Call a.quit() or a.exit() to quit the application.
    // A not very useful example would be including
    // #include <QTimer>
    // near the top of the file and calling
    // QTimer::singleShot(5000, &a, &QCoreApplication::quit);
    // which quits the application after 5 seconds.

    // If you do not need a running Qt event loop, remove the call
    // to a.exec() or use the Non-Qt Plain C++ Application template.

    QThread t1;
    QThread t2;
    QObject::connect(&t1, &QThread::started, threadFunc);
    QObject::connect(&t2, &QThread::started, threadFunc);
    t1.start();
    t2.start();

    return a.exec();
}

注意点:

必须保证lock()unlock()成对出现!如果在临界区中抛出异常、提前 return,会导致unlock()无法执行,其他线程永远拿不到锁(死锁)。

(2)QMutexLocker

QMutexLocker是 Qt 提供的RAII 风格的锁管理类 (RAII:资源获取即初始化),可以理解为QMutex的 "自动管家"------ 它会在创建时自动加锁,销毁时自动解锁,彻底避免手动加解锁的漏写 / 错写问题。

核心逻辑:

构造函数:接收一个QMutex对象的指针 / 引用,自动调用mutex->lock();

析构函数:当QMutexLocker对象超出作用域(比如函数结束、遇到break/return),自动调用mutex->unlock()。

使用示例,替换上面的QMutex

C++ 复制代码
#include <QMutexLocker>
#include <QThread>
#include <QDebug>

QMutex mutex;
int sharedValue = 0;

void threadFunc() 
{
    for (int i = 0; i < 5; ++i) 
    {
        QMutexLocker locker(&mutex); // 自动加锁
        sharedValue++;
        qDebug() << QThread::currentThreadId() << "sharedValue:" << sharedValue;
        // 无需手动解锁!locker析构时自动解锁(即使这里写return也不影响)
        QThread::msleep(10);
    } // locker超出作用域,析构→自动解锁
}

额外实用方法

unlock():手动提前解锁(比如临界区提前结束);

relock():重新加锁(如果提前解锁后需要再次保护资源)。

(3)QMutex vs QMutexLocker 核心对比

特性 QMutex QMutexLocker
加解锁方式 手动调用 lock ()/unlock () 自动加锁(构造)、自动解锁(析构)
安全性 低(易漏写 unlock ()) 高(RAII 机制,避免死锁)
代码复杂度 高(需手动管理成对调用) 低(一行代码搞定加解锁)
使用场景 简单场景 / 需手动控制解锁 绝大多数多线程临界区保护(推荐优先用)

二、总结

  1. QMutex 是基础互斥锁,提供手动加解锁能力,核心作用是保护共享资源,但需严格保证lock()/unlock()成对调用;
  2. QMutexLockerQMutex的封装,基于 RAII 机制自动管理锁的生命周期,能避免因异常 / 提前退出导致的死锁,是 Qt 中推荐的锁使用方式;
  3. 实际开发中,优先使用 QMutexLocker,仅在需要手动精细控制解锁时机时(比如临界区中间需要临时解锁)才直接用 QMutex。
相关推荐
用户805533698032 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner2 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz7 天前
QML Hello World 入门示例
qt
xcyxiner10 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner11 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner12 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能14 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G14 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt