QThread是一个低级(low-level)类,适合用于显式地构建长期运行的线程。
QtConcurrent是一个命名空间,提供了用于编写并发软件的更高层次的类和算法。该命名空间中有一个重要的类,QThreadPool,这是一个管理线程池的类。每个Qt应用程序都有一个QThreadPool::globalInstance()函数,它带有一个推荐的最大线程数,在大多数系统上,处理核的数量就是该值的默认值。
借助于QtConcurrent中函数式的map/filter/reduce算法(它们可将函数并行用到容器中的每一项),通过将进程分布在由线程池管理的多个线程上,可编写一个能够自动利用系统多核的程序。
线程指南
一般情况下,要尽可能避免使用多线程,而是用Qt事件循环与QTimer、非阻塞I/O操作、信号以及短持续时间槽相结合的方法来代替。此外,可以在主线程中长期运行的循环调用QApplication::processEvents(),以使执行工作时图形用户界面可以保持响应。
要驱动动画(animation),建议使用QTimer,QTimeLine或者动画框架(Animation Framework)。这些API并不需要额外创建其它线程。它们允许访问动画代码中的GUI对象而且不会妨碍图形用户界面的响应。
如果要完成CPU密集型工作并希望将其分配给多个处理核,可以把工作分散到QRunnable并通过以下这些推荐做法来实现线程的安全。
1)无论何时,都尽可能使用QtConcurrent算法把CPU密集型计算工作分散给多线程,而不是自己编写QThread代码。
2)除了主线程以外,不要从其它任何线程访问图形用户界面(这也包括那些由QWidget派生的类、QPixmap和那些与显卡相关的类)。这包括读取操作,比如查询QLineEdit中输入的文本。
3)要其他线程中处理图像,使用QImage而不是QPixmap。
4)不要调用QDialog::exec()或者从除主线程之外的任何线程创建QWidget或QIODevice的子类。
5)使用QMutex、QReadWriteLock或者QSemaphone以禁止多个线程同时访问临界变量。
6)在一个拥有多个return语句的函数中使用QMutexLocker(或者QReadLocker、QWriteLocker),以确保函数从任意可能的执行路径均可释放锁。
&nb