Qt——多线程

一、QThread类

如果要设计多线程程序,一般是从QThread继承定义一个线程类,并重新定义QThread的虚函数 run() ,在函数 run() 里处理线程的事件循环。

应用程序的线程称为主线程 ,创建的其他线程称为工作线程 。主线程的 start() 函数会在其内部调用 run() 函数,然后 exec() 函数会让 run() 函数保持运行,进入工作线程的事件循环,随时接收系统事件。如下图所示:

注:MyThread 继承于 QThread。

二、线程同步

1. 互斥量(Mutex)

在多线程程序中,线程之间可能需要访问同一个变量(临界资源),或一个线程需要等待另一个线程完成某个操作才产生相应的动作。QMutexQMutexLocker 都是基于互斥量的线程同步类。

QMutexlock() 函数用来锁定互斥量,unlock() 函数用来解锁互斥量。这两个方法必须配对使用。其次还要一个 tryLock() 函数,如果函数返回 true 则表示成拿到了共享资源。示例如下:

cpp 复制代码
QMutex  mutex;

void MyThread::run() {
    while(true) {
        mutex.lock();       //锁定互斥量
        ...
        mutex.unlock();     //解锁互斥量
    } 
}

QMutexLocker和 QMutex 相比,是一个简化了互斥量处理的类。它的构造函数接受互斥量作为参数并将其锁定,其析构函数则将此互斥量解锁。QMutexLocker 会使其在生存期内的代码片段得到保护。示例如下:

cpp 复制代码
QMutex  mutex;

void MyThread::run() {
    while(true) {
         if (mutex.tryLock(500))    //尝试锁定一个信号量,最多等500ms
         {
            QMutexLocker locker(&mutex);    //锁定mutex,超出if范围自动解锁
            ...  
         }
    } 
}

2. 读写锁(ReadWriteLock)

使用互斥量时存在一个问题,那就是每次只有一个线程获得互斥量的使用权限。如果在一个程序中有多个线程读取 某个变量,那么这个变量就不是临界资源,是允许同时访问的。这时我们就需要 Qt 提供的读写锁类 QReadWriteLock,它是基于读或写的方式进行代码片锁定的。

其中 lockForRead() 函数会以只读方式锁定资源,锁定后其他线程只能读不能写。 lockForWrite() 函数以写的方式锁定资源,锁定后其他线程不能读也不能写。

3. 条件等待(WaitCondition)

QWaitCondition 提供了一种改进的线程同步方法。它通过与QReadWriteLock 结合使用,可以使一个线程在满足一定条件下通知其他多个线程,使其他多个线程即时进行响应。

其中 wait() 函数用于释放互斥量,**wakeAll()**函数用于唤醒所有处于等待状态的线程。wait() 函数定义如下:

cpp 复制代码
bool wait(QReadWriteLock *readWriteLock, unsigned long time)

QWaitCondition 一般用于生产者/消费者(producer/consumer)问题。暂且假设缓冲区一直有资源且无限大,示例代码如下:

cpp 复制代码
QReadWriteLock rwLocker;    //读写锁

QWaitCondition waiter;    //控制线程同步的对象

// 生产者
void ProducerThread::run() {
    while(1) {
        rwLocker.lockForWrite();    //以写方式锁定
        ...
        rwLocker.unlock();          //解锁
        waiter.wakeAll();       //唤醒其他等待的线程
        msleep(500);    //线程休眠500ms
    }
}

// 消费者1
void ConsumerThread1::run() {
    while(1) {
        rwLocker.lockForRead();     //以只读方式锁定
        waiter.wait(&rwLocker);     //等待被唤醒
        ...
        rwLocker.unlock();          //解锁
    }
}

// 消费者2
void ConsumerThread2::run() {
    while(1) {
        rwLocker.lockForRead();     //以只读方式锁定
        waiter.wait(&rwLocker);     //等待被唤醒
        ...
        rwLocker.unlock();          //解锁
    }
}

4. 信号量(Semaphore)

信号量与互斥量类似,但二者又有区别。一个互斥量只能被锁定一次 ,而信号量可以被多次利用。信号量通常用来保护一定数量的相同资源,如双缓冲区。

QSemaphore 就是 Qt 实现信号量功能的类。其中 acquire(int n) 用于尝试获得n个资源,release(int n) 用于释放n个资源。**available()**用于返回当前信号量的可用资源个数。

相关推荐
Ustinian_31021 分钟前
【C/C++】For 循环展开与性能优化【附代码讲解】
c语言·开发语言·c++
牵牛老人30 分钟前
Qt 插件开发全解析:从接口定义,插件封装,插件调用到插件间的通信
开发语言·qt
22jimmy2 小时前
JavaWeb(二)CSS
java·开发语言·前端·css·入门·基础
机器视觉知识推荐、就业指导4 小时前
面试问题详解五:Qt 信号与槽的动态管理
开发语言·qt
vvilkim5 小时前
Java主流框架全解析:从企业级开发到云原生
java·运维·云原生
MZ_ZXD0016 小时前
springboot汽车租赁服务管理系统-计算机毕业设计源码58196
java·c++·spring boot·python·django·flask·php
A 计算机毕业设计-小途6 小时前
大四零基础用Vue+ElementUI一周做完化妆品推荐系统?
java·大数据·hadoop·python·spark·毕业设计·毕设
岁忧8 小时前
(nice!!!)(LeetCode 每日一题) 679. 24 点游戏 (深度优先搜索)
java·c++·leetcode·游戏·go·深度优先
小欣加油8 小时前
leetcode 3 无重复字符的最长子串
c++·算法·leetcode
四维碎片10 小时前
【Qt】线程池与全局信号实现异步协作
开发语言·qt·ui·visual studio