线程

最后更新于: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|×|×| √| |面向任务|× | √|√ | |内建对暂停/恢复/取消的支持|× | ×| √| |具有优先级| √| ×| ×| |可运行事件循环| √| ×|× |
';