线程
最后更新于:2022-04-02 02:12:53
[TOC]
## 线程
1. QThread 是个 low-level 的类,适用于长期显示的构建长期运行的线程
2. QtConCurrent 是一个命名空间,提供了用于编写并发软件的更高层次的类和算法
3. QtConCurrent 的 QThreadPool 是管理线程池的类,每个Qt应用程序都带有 QThreadPool::globInstance()函数,它带有推荐的最大线程数(一般为核数)
4. 令模式和利用 QtConcurrent::run()工作时可把QRunnable用作基类。在这些情况下,无须显式地创建线程或者直接管理它们,只需简单地把工作片段描述为具有正确接口的对象即可。
## 避免使用线程场景
- 一般情况下,要尽可能避免使用线程.
- 而是用 Qt 事件循环与 QTimer 、非阻塞 I/O 操作、信号以及短持续时间槽相结合的方法来代替。
- 此外,可以在**主线程中长期运行的循环调用** Application::processEvents(),以使执行工作时图形用户界面可以保持响应
- 要驱动动画( animation),建议使用 QTimer, QTimerLine 或者动画框架( Animation Framework)。这些AP并不需要额外创建其他线程。它们允许访问动画代码中的 GUI 对象而且不会妨碍图形用户界面的响应。
## 使用线程场景
如果要完成CPU密集型工作并希望将其分配给多个处理核,可以把工作分散到Runnable并通过以下这些推荐做法来实现线程的安全。
- 无论何时,都尽可能使用 QConCurernt 算法把 CPU 密集型计算工作分散给多线程,而不是自己编写 QThread代码。
- 除了主线程以外,不要从其他任何线程访问图形用户界面(这也包括那些由 QWdiget 类, QPixMap 和其他与显卡相关的类)。这包括读取操作,比如查询 QLineEdit 中输入的文本
- 要在其他线程中处理图像,使用 QImage 而不是 QPixMap
- 子线程中不要调用 QDialog::exec() 或者从除主线程之外的任何线程创建 QWidget QIODevice 的子类
- 使用 QMutex, QReadWriteLock 或者 QSemaphone 以禁止多个线程同时访间临界变量。
- 在一个拥有多个 return 语句的函数中使用 锁,确保锁均能释放
- 创建 QObject 的线程,也称线程关联( thread affinity),负责执行那个 QObject的槽。
- 通过从run()函数直接或者间接地调用 QThread::exec(),可以让线程进入事件循环。
- 利用 Application::postEvent()分发事件,或使用队列式的信号槽连接,都是用于线程间通信的安全机制—但需要接收线程处于事件循环中。
- **确保每个跨线程连接的参数类型都用 qRegisterMetafype() 注册过**
## QRunnable 与 QThreads 区别
1. 与外界通信方式不同。由于QThread是继承于QObject的,但QRunnable不是,所以在QThread线程中,可以直接将线程中执行的结果通过信号的方式发到主程序,而QRunnable线程2不能用信号槽,只能通过别的方式,等下会介绍。
2. 启动线程方式不同。QThread线程可以直接调用start()函数启动,而QRunnable线程需要借助QThreadPool进行启动。
3. 资源管理不同。QThread线程对象需要手动去管理删除和释放,而QRunnable则会在QThreadPool调用完成后自动释放。
4. QThread适用于那些常驻内存的任务。而且QThread可以通过信号/槽的方式与外界进行通信。而QRunnable则适用于那些不常驻内存,任务数量比较多的情况。
## QThread / QRunnable / QtConcurrent 区别
|特性|QThread|QRunnable|QtConcurrent|
|---|---|---|---|
|高级API|×|×| √|
|面向任务|× | √|√ |
|内建对暂停/恢复/取消的支持|× | ×| √|
|具有优先级| √| ×| ×|
|可运行事件循环| √| ×|× |
';