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()**用于返回当前信号量的可用资源个数。

相关推荐
用户298698530143 分钟前
Java 实现 Word 文档文本与图片提取的方法
java·后端
Quz36 分钟前
QML Hello World 入门示例
qt
SimonKing1 小时前
铁子,IntelliJ IDEA 2026.1.3来了,升不升?
java·后端·程序员
咖啡八杯12 小时前
GoF设计模式——策略模式
java·后端·spring·设计模式
用户1285261160220 小时前
我把祖传Java项目重构后,接口响应从3s砍到了200ms,只改了这几行代码
java
Linsk20 小时前
组件 = 模板 + 业务逻辑
java·前端·vue.js
星沉远浦21 小时前
用Gemini高效解决Java代码报错难以定位的问题
java
博客18001 天前
酷宝的使用方法,超好用的免费界面库,C++、MFC可用
c++·mfc·界面库·库来帮·酷宝
用户298698530141 天前
Word 文档字符级格式化:Java 实现方案详解
java·后端