QThread 的使用方法 注意事项
2015-10-27 15:05
435 查看
起源
昨天不小心看到Qt开发人员( Bradley T. Hughes)Blog中的一片文章 you are-doing-it-wrong 。 结果看得头昏脑胀:好歹也自学了近1年的Qt,也一直很小心、很认真地阅读Qt和manual和例子等资料,却被突然告知,QThread的正确使用方法是一种自己从没见过,而且Qt
manual、example、书籍中都没有提到过的一种方法。到底怎么了...
莫非manual、exmaple以及资料中的介绍都是错的??
认真看看其他的人的评论,总算理清了一点头绪。所有事情源于 QThread 的事件循环!
QThread 的两种使用方法
1. 不使用事件循环。这是官方的 Manual 、example 以及相关书籍中都介绍的一种的方法。
a. 子类化 QThread
b. 重载 run 函数,run函数内有一个 while 或 for 的死循环
c. 设置一个标记为来控制死循环的退出。
如果使用这一方法,QThread::quit()没有效果。因为这个线程根本就不需要事件循环。这种情况想退出,直接使用QT很不推荐的terminate().
最常用的就是这种方法。
2. 使用事件循环。(博客 you are-doing-it-wrong 批驳的就是这种情况下的 一种用法。)
a. 子类化 QThread,
b. 重载 run 使其调用 QThread::exec()
c. 并为该类定义信号和槽,这样一来,由于槽函数并不会在新开的 thread 运行,很多人为了解决这个问题在构造函数中调用
另外:
在Qt4.3(包括)之前,run 是虚函数,必须子类化QThread来实现run函数。
而从Qt4.4开始,qthreads-no-longer-abstract
,run 默认调用 QThread::exec() 。这样一来不需要子类化 QThread 了,只需要子类化一个 QObject 就够了,这正是被 Bradley T. Hughes推荐的方法。
终于看懂了,但
不管怎么说,都应该是 QThread 当初的设计导致的这种问题,而所有文档和例子中都没有提到该如何使用Qthread 进一步加剧了对QThread的这种误用。
另注:1.QThread对象从建立起就是活跃的,所以大牛Bradley T. Hughes把QObject对象移动到QThread中,对QObject的操作是完全合理合法合逻辑的。
2.既然使用了多线程,就必须考虑互斥问题,QThread的所有slot函数都是可多重入和不安全的(具体参见QT的可重入和线程安全)。而且在此之外,除了GUI类对象必须在主进程(不可重入,从而保证了线程安全),互斥锁一类的类可重入和线程安全外。所以的QObject对象都不是线程安全的,换句话说,在主线程内为单线程设计的QObject子类对象,如果没有对其slot函数做互斥处理,就会出现因signal调用而反复重入某个slot函数的情况,反而成了多线程。(C++对象,由于是顺序调用,所以在单线程下不会出现这个问题)。这时需要依据情况考虑互斥锁。
3.使用大牛Bradley
T. Hughesr的方法把QObject对象移动到QThread中,要使用signal+slot的方式来调用函数,这样的话,通过QT消息机制,QObject被调用的函数是在线程内执行。如果直接(QObject对象).abc()的话,这个成员函数是在主进程内执行,可能会出现"QObject::killTimer: timers cannot be stopped from another thread"的运行错误。
相关链接:
http://labs.qt.nokia.com/blogs/2010/06/17/youre-doing-it-wrong/ http://labs.qt.nokia.com/blogs/2006/12/04/threading-without-the-headache/ http://labs.qt.nokia.com/blogs/2007/07/05/qthreads-no-longer-abstract/ http://gitorious.org/qthreadhowto/qthreadhowto/trees/master http://blog.exys.org/entries/2010/QThread_affinity.html http://thesmithfam.org/blog/2010/02/07/talking-to-qt-threads/
昨天不小心看到Qt开发人员( Bradley T. Hughes)Blog中的一片文章 you are-doing-it-wrong 。 结果看得头昏脑胀:好歹也自学了近1年的Qt,也一直很小心、很认真地阅读Qt和manual和例子等资料,却被突然告知,QThread的正确使用方法是一种自己从没见过,而且Qt
manual、example、书籍中都没有提到过的一种方法。到底怎么了...
莫非manual、exmaple以及资料中的介绍都是错的??
认真看看其他的人的评论,总算理清了一点头绪。所有事情源于 QThread 的事件循环!
QThread 的两种使用方法
1. 不使用事件循环。这是官方的 Manual 、example 以及相关书籍中都介绍的一种的方法。
a. 子类化 QThread
b. 重载 run 函数,run函数内有一个 while 或 for 的死循环
c. 设置一个标记为来控制死循环的退出。
如果使用这一方法,QThread::quit()没有效果。因为这个线程根本就不需要事件循环。这种情况想退出,直接使用QT很不推荐的terminate().
最常用的就是这种方法。
2. 使用事件循环。(博客 you are-doing-it-wrong 批驳的就是这种情况下的 一种用法。)
a. 子类化 QThread,
b. 重载 run 使其调用 QThread::exec()
c. 并为该类定义信号和槽,这样一来,由于槽函数并不会在新开的 thread 运行,很多人为了解决这个问题在构造函数中调用
moveToThread(this); 而争论和不解正是这样的一条语句造成的。Bradley T. Hughes 给出说明是: QThread 应该被看做是操作系统线程的接口或控制点,而不应该包含需要在新线程中运行的代码。需要运行的代码应该放到一个QObject的子类中,然后将该子类的对象moveToThread到新线程中。
另外:
在Qt4.3(包括)之前,run 是虚函数,必须子类化QThread来实现run函数。
而从Qt4.4开始,qthreads-no-longer-abstract
,run 默认调用 QThread::exec() 。这样一来不需要子类化 QThread 了,只需要子类化一个 QObject 就够了,这正是被 Bradley T. Hughes推荐的方法。
终于看懂了,但
不管怎么说,都应该是 QThread 当初的设计导致的这种问题,而所有文档和例子中都没有提到该如何使用Qthread 进一步加剧了对QThread的这种误用。
另注:1.QThread对象从建立起就是活跃的,所以大牛Bradley T. Hughes把QObject对象移动到QThread中,对QObject的操作是完全合理合法合逻辑的。
2.既然使用了多线程,就必须考虑互斥问题,QThread的所有slot函数都是可多重入和不安全的(具体参见QT的可重入和线程安全)。而且在此之外,除了GUI类对象必须在主进程(不可重入,从而保证了线程安全),互斥锁一类的类可重入和线程安全外。所以的QObject对象都不是线程安全的,换句话说,在主线程内为单线程设计的QObject子类对象,如果没有对其slot函数做互斥处理,就会出现因signal调用而反复重入某个slot函数的情况,反而成了多线程。(C++对象,由于是顺序调用,所以在单线程下不会出现这个问题)。这时需要依据情况考虑互斥锁。
3.使用大牛Bradley
T. Hughesr的方法把QObject对象移动到QThread中,要使用signal+slot的方式来调用函数,这样的话,通过QT消息机制,QObject被调用的函数是在线程内执行。如果直接(QObject对象).abc()的话,这个成员函数是在主进程内执行,可能会出现"QObject::killTimer: timers cannot be stopped from another thread"的运行错误。
相关链接:
http://labs.qt.nokia.com/blogs/2010/06/17/youre-doing-it-wrong/ http://labs.qt.nokia.com/blogs/2006/12/04/threading-without-the-headache/ http://labs.qt.nokia.com/blogs/2007/07/05/qthreads-no-longer-abstract/ http://gitorious.org/qthreadhowto/qthreadhowto/trees/master http://blog.exys.org/entries/2010/QThread_affinity.html http://thesmithfam.org/blog/2010/02/07/talking-to-qt-threads/
相关文章推荐
- QT5入门之17 - 文件选择对话框
- win7 32bit 用qmake编译qt程序
- QT5入门之16 - 设置按钮提示
- QT5入门之15 - qr函数
- qtp传参的注意要点,及小技巧
- qt中某个类的头文件无法找到
- qt环境变量配置
- Qt QLabel::setBuddy函数
- Qt使用教程之创建一个基于Qt部件的应用程序(一)
- Qt concurrent run()函数使用
- Qt之无边框自定义最小化、关闭按钮并实现窗口移动
- Qt::WA_StaticContents的作用
- QT程序Release后无法连接数据库的问题
- qt5和opencv3在linux上安装配置
- There's no Qt version assigned to this project for platform x64. Please use the 'change Qt version
- Qt中 QGLWidget碰到no such file or directory的解决办法
- Qt之四方分割器QuadSplitter
- Qt5+VS2013兼容XP方法
- 学习Qt之简单计算器
- Qt添加界面文件的背景图片