18. Qt系统相关:多线程
一、概述
在Qt中,使用QThread类对系统线程进行了封装。QThread代表一个在应用程序中可独立控制的线程,也可以和进程中的其他线程共享数据。
二、QThread常用API
三、QThread使用
- 自定义一个类,继承自QThread,并且只有一个线程处理函数(和主线程不是同一个线程),这个线程处理函数主要就是重写父类的run函数;
- 线程处理函数中实现需要线程执行的逻辑;
- 通过类对象调用start()函数启动线程(不能直接调用run函数);
- 线程处理函数执行结束后,可以通过自定义信号来通知主线程;
- 关闭线程。
注意:
1、除了UI线程外,其他线程内不允许直接操作UI图像界面,可以通过信号槽机制通知UI线程,由UI线程进行统一处理。
2、connect()函数第五个参数表示为信号槽的连接方式,只有在多线程时才有意义。
四、线程安全
Qt中实现线程互斥和同步常用的类有:
- 互斥锁:QMutex、QMutexLocker
- 条件变量:QWaitCondition
- 信号量:QSemaphore
- 读写锁:QReadLocker、QWriteLocker、QReadWriteLock
4.1 互斥锁
4.1.1 QMutex
QMutex是Qt框架提供的互斥锁类,用于保护共享资源的访问,实现线程间的互斥操作。
4.2.2 QMutexLocker
QMutexLocker是QMutex的辅助类,使用RAII方式对互斥锁进行上锁和解锁操作。用于简化互斥锁的上锁解锁操作,避免因忘记解锁导致的死锁等问题。
{
QMutexLocker locker(&m_mutex);
// 访问共享资源
// 函数作用域结束时,locker自动解锁
}
4.2 独写锁
4.2.1 QReadWriteLock
QReadWriteLock是Qt框架提供的读写锁,用于控制独写操作的并发访问。
4.2.2 QReadLocker
QReadLocker 是RAII风格的读锁管理类,析构时自动解锁;用于读操作上锁,允许多个线程同时读取共享资源。
4.2.3 QWriteLocker
QWriteLocker 是RAII风格的写锁管理类,析构时自动解锁;用于写操作上锁,只允许一个线程写入共享资源。
4.3 条件变量
在多线程编程中,假设除了等待操作系统正在执行的线程外,某个线程还必须等待某些条件满足才能执行,这时就会出现问题。这种情况下,线程会很自然的使用锁机制在阻塞其他线程,因为这只是线程的轮流使用,并且该线程等待某些特定条件,人们会认为需要等待的线程在释放互斥锁或读写锁之后进入了睡眠状态,这样其他线程就可以继续运行。当特定条件满足时,等待条件的线程被另一个线程唤醒。
在Qt中,专门提供了QWaitCondition类来解截上述问题。
特点:QWaitCondition是Qt框架提供的条件变量类,用于线程间的消息通信和同步。
用途:在某个条件满足时等待或唤醒线程,用于线程间的同步和协调。
4.4 信号量
在多线程编程中,有时需要确保多个线程可以相应的访问一个数量有限的相同资源。例如,运行程序的设备可能是非常有限的内存,因此我们更希望需要大量内存的线程将这一情况考虑子啊内,并根据可用的内存数量进行相关操作,多线程编程中类似问题通常使用信号量来处理。
信号量类似于增强的互斥锁,不仅能完成上锁和解锁操作,而且可以跟踪可用资源的数量。
特点:QSemaphore是Qt框架中封装用于提供计数信号量的类,用于控制同时访问共享资源的线程数量。
用途:限制并发线程数量,用于解截一些资源有限的问题。