1. QThread
两种方式,其一是任何继承QObject的类都有moveToThread的方法,利用该方法可以将当前类(继承QObject)中耗时的操作,移动到新线程执行,避免阻塞主线程。其二是通过继承QThread类,重载其run()函数,当前类中耗时的操作在该函数体中实现,但是要注意的一个问题是,继承自QThread的类的构造函数,也即该类的实体在原线程中,而run函数体则在新线程中执行,所以,需要特别注意的是,要避免该类的成员变量被两个线程同时访问,这样会造成不安全性(例如,一个线程执行时,另一个线程修改了成员变量的值,这样就可能出现冲突或者错误,如果需要,那么应该考虑异步运算,利用加锁机制)。此外,继承类中的所有槽函数实现也将是在原来的线程里面运行,只有run函数才会在新线程执行,如果希望槽函数在新线程执行,那么可以使用moveToThread方法(worker-object)来将整个类移到新线程中去,或者在其他地方实现槽函数。
2. QThreadPool
每一个Qt程序有一个QThreadPool类来管理其所有的线程(分配和回收),使用QThread::gloabalInstance可以获得之。当需要执行耗时操作时,为了避免阻塞主线程,可以定义一个处理类使之继承自QRunable,然后重载其run()函数,获取全局QThreadPool对象并调用start函数例如:
此处的hello对象,当run执行完成,QThreadPool会自动回收,若想自己管理,可以通过QRunnable::setAutoDelete()来自定义管理。
3. QtConcurrent命名空间
使用时记得在pro文件中写上QT += concurrent
它是多线程的high-level实现,前面的QThread和QThreadPool所实现的多线程实际意义上只是不阻塞主线程,另外开辟一个线程来执行耗时操作。实质上并没有加速功能。而QtConcurrent命名空间内的函数实现了任务分发的并行计算,可以提高运算速度。
主要函数有:map、mapReduce、reduce、map-reduce、filter、filter-reduce等(详细见Qt帮助文档)
QConcurrent::Run(),需要注意的是run函数实现的线程不支持cancel(),pause()或者progress reporting,只能监测其状态(running/finished)以及获得返回值(通过QFuture,T与run函数类型一样,支持void)。所以若将QprogressDialog或者QProgressBar的cancel信号与线程的cancel连接是不会起作用的,但是map,reduce等函数可以接受cancel信号。Run开的线程并非一定立即执行,它会等待QThreadPool分配可用的线程。