本文翻译自: https://woboq.com/blog/qthrea...
原做者: Olivier Goffart
发布时间:2013年1月22日
这篇文章是关于QThread的使用的。这是对我当时的同事Brad三年前的博客帖子的回答:"您作错了"。 html
Brad在他的博客文章中解释说,他看到许多用户经过对QThread进行子类化,在该子类中添加一些槽并在构造函数中执行如下操做来滥用QThread:async
moveToThread(this);
他们把线程移动到本身类内。正如Brad所提到的,这是错误的:QThread应该是管理线程的接口。所以,应该在建立线程中使用它。 函数
这样,就没法在该线程中运行QThread对象中的槽,而且在QThread的子类中具备槽是一种很差的作法。 性能
可是,Brad继续并彻底不鼓励使用QThread的任何子类。他声称这违反了正确的面向对象设计。这是我不一样意的地方。放入代码run()
是扩展QThread的一种有效的面向对象方法:QThread表示一个仅启动事件循环的线程,子类表示一个被扩展以执行其工做的线程run()
。 this
Brad上任后,该社区的一些成员就反对对QThread进行子类化进行了讨伐。问题在于,有不少彻底合法的缘由能够继承QThread。 线程
在Qt 5.0和Qt 4.8.4中,更改了QThread的文档,所以示例代码不涉及子类。查看Qt 4.8 QThread文档的第一个代码示例(更新的文档已经修复)。它具备许多样板行,仅用于在线程中运行一些代码。并且甚至存在泄漏:QThread永远不会退出并被销毁。 翻译
我在IRC上被问到一个用户的问题,该用户遵循该示例,以便在线程中运行一些简单的代码。他很难弄清楚如何正确销毁线程。这就是促使我撰写此博客条目的缘由。 设计
若是容许子类化QThread,那么您将得到:code
class WorkerThread : public QThread { void run() { // ... } }; void MyObject::startWorkInAThread() { WorkerThread *workerThread = new WorkerThread; connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater())); workerThread->start(); }
此代码再也不泄漏,而且更加简单,而且不会建立无用的对象,所以开销较小。 server
Qt线程示例threadedfortuneserver是使用此模式运行阻塞操做的示例,而且比使用worker对象的等效示例要简单得多。
我已经向文档提交了补丁, 以避免再次阻止对QThread的子类化。
QThread的级别很低,您最好使用更高级别的API,例如QtConcurrent。
如今,QtConcurrent有其自身的一系列问题:它与单个线程池绑定,所以若是要运行阻塞操做,它不是一个好的解决方案。在其实现中还存在一些问题,这些问题会带来一些性能开销。全部这些都是能够修复的。也许甚至Qt 5.1也会有所改进。
一个很好的选择也是C ++ 11与标准库 std::thread 和std::async它们如今在一个线程中运行的代码的标准方式。好消息是它仍然能够在Qt上正常工做:全部其余Qt线程原语均可以与本机线程一块儿使用。(若是须要,Qt将自动建立一个QThread来建立)