movetothread this和派生自qthread的区别

您所在的位置: &
解析Qt中QThread使用方法(1)
解析Qt中QThread使用方法(1)
本文介绍了Qt中QThread使用方法,在本片文章中反复提到了线程的使用,详细内容请参考本文,QThread的使用方法:#include 继承了Qt。
本文讲述的是在Qt中QThread使用方法,QThread似乎是很难的一个东西,特别是信号和槽,有非常多的人(尽管使用者本人往往不知道)在用不恰当(甚至错误)的方式在使用 QThread,随便用google一搜,就能搜出大量结果出来。无怪乎Qt的开发人员 Bradley T. Hughes 声嘶力竭地喊you are-doing-it-wrong
和众多用户一样,初次看到这个时,感到 Bradley T. Hughes有 些莫名奇妙,小题大作。尽管不舒服,当时还是整理过一篇博客QThread 的使用方法
时间过去3个月,尽管依然没怎么用thread;但今天csdn论坛中有人问到这个问题,想想还是尽我所能整理一下吧。提升自己,方便他人,何乐而不为呢?
QThread东西还是比较多的,而且我对底层对象了解有限,仅就一点进行展开(或许是大家最关心的一点):QThread中的slots在那个线程中执行?
QThread::run
run 函数是做什么用的?Manual中说的清楚:
run 对于线程的作用相当于main函数对于应用程序。它是线程的入口,run的开始和结束意味着线程的开始和结束。 原文如下:
The&run()&implementation&is&for&a&thread&what&the&main()& &entry&point&is&for&the&application.&All&code&executed&in&a&call&stack&that&starts&in&the&run()& &function&is&executed&by&the&new&thread,&and&the&thread&finishes&when&the&function&returns.&&
这么短的文字一眼就看完了,可是,这是什么意思呢?又能说明什么问题呢?看段简单代码:
class&Thread:public&QThread&{&&&&& &Q_OBJECT&public:&&&&& &Thread(QObject*&parent=0):QThread(parent){}& &public&slots:&&&&& &void&slot()&{&...&}&signals:&&&&& &void&sig();&protected:&&&&& &void&run()&{&...}&};&& &int&main(int&argc,&char**&argv)&{&...&&&&&Thread&&...&}&
对照前面的定理,run函数中的代码时确定无疑要在次线程中运行的,那么其他的呢?比如 slot 是在次线程还是主线程中运行?
QObject::connect
涉及信号槽,我们就躲不过 connect 函数,只是这个函数大家太熟悉。我不好意思再用一堆废话来描述它,但不说又不行,那么折中一下,只看它的最后一个参数吧(为了简单起见,只看它最常用的3个值):
1、自动连接(Auto Connection)
这是默认设置
如果发送者和接收者处于同一线程,则等同于直接连接
如果发送者和接受者位于不同线程,则等同于队列连接
也就是这说,只存在下面两种情况
2、直接连接(Direct Connection)
当信号发射时,槽函数将直接被调用。
无论槽函数所属对象在哪个线程,槽函数都在发射者所在线程执行。
3、队列连接(Queued Connection)
当控制权回到接受者所在线程的事件循环式,槽函数被调用。
槽函数在接收者所在线程执行。
同前面一样,这些文字大家都能看懂。但含义呢?
不妨继续拿前面的例子来看,slot 函数是在主线程还是次线程中执行呢?
定理二强调两个概念:发送者所在线程 和 接收者所在线程。而 slot 函数属于我们在main中创建的对象 thread,即thread属于主线程
队列连接告诉我们:槽函数在接受者所在线程执行。即 slot 将在主线程执行
直接连接告诉我们:槽函数在发送者所在线程执行。发送者在那个线程呢??不定!
自动连接告诉我们:二者不在同一线程时,等同于队列连接。即 slot 在主线程执行
要彻底理解这几句话,你可能需要看Qt meta-object系统和Qt event系统)
如果上两节看不懂,就记住下面的话吧(自己总结的,用词上估计会不太准确)。
QThread 是用来管理线程的,它所处的线程和它管理的线程并不是同一个东西
QThread 所处的线程,就是执行 QThread t(0) 或 QThread * t=new QThread(0) 的线程。也就是咱们这儿的主线程
QThread 管理的线程,就是 run 启动的线程。也就是次线程
因为QThread的对象在主线程中,所以他的slot函数会在主线程中执行,而不是次线程。除非:QThread 对象在次线程中
slot 和信号是直接连接,且信号所属对象在次线程中
但上两种解决方法都不好,因为QThread不是这么用的(Bradley T. Hughes)
好了,不在添加更多文字了,看代码,估计咱们都会轻松点
主线程(信号)QThread(槽)
这是Qt Manual 和 例子中普遍采用的方法。 但由于manual没说槽函数是在主线程执行的,所以不少人都认为它应该是在次线程执行了。
定义一个 Dummy 类,用来发信号
定义一个 Thread 类,用来接收信号
重载 run 函数,目的是打印 threadid
/*! &*&\file&main.cpp &* &*&Copyright&(C)&2010,&dbzhang800 &*&All&rights&reserved. &* &*/ &#include&/QCoreApplication& &#include&/QObject& &#include&/QThread& &#include&/QDebug&&class&Dummy:public&QObject&{&&&&& &Q_OBJECT&public:&&& &Dummy(){}&public&slots:&&void&emitsig()& &{&&&&&&&&&emit&sig();&&&&& &}&signals:&&&&&void&sig();& &};&& &class&Thread:public&QThread&{&&&& &&Q_OBJECT&public:&&&&& &Thread(QObject*&parent=0):QThread(parent)&{&&&//moveToThread(this);&}& &public&slots:&&&&&void&slot_main()&&&&&{&&&&&&&&& &qDebug()&from&thread&slot_main:&&();&&&&& &}&protected:&&&&&void&run()&&&&&{&&&&&&&&& &qDebug()&thread&thread:&();&&&&&&&&& &exec();&&&&& &}& &};& &#include&&main.moc&&int&main(int&argc,&char&*argv[])&{&&&&& &&QCoreApplication&a(argc,&argv);&&&&& &qDebug()&main&thread:&();&&&& &&Thread&&&&&& &Dummy&&&&& &&QObject::connect(&dummy,&SIGNAL(sig()),&&thread,&SLOT(slot_main()));&&&&& &thread.start();&&&& &&dummy.emitsig();&&&&& &return&a.exec();&}&
然后看到结果(具体值每次都变,但结论不变)
main&thread:&0x1a40&from&thread&slot_main:&0x1a40&thread&thread:&0x1a48&
看到了吧,槽函数的线程和主线程是一样的!
如果你看过Qt自带的例子,你会发现 QThread 中 slot 和 run 函数共同操作的对象,都会用QMutex锁住。为什么?因为slot和run处于不同线程,需要线程间的同步!
如果想让槽函数slot在次线程运行(比如它执行耗时的操作,会让主线程死掉),怎么解决呢?
注意:发送dummy信号是在主线程, 接收者 thread 也在主线程中。 参考我们前面的结论,很容易想到: 将 thread 放到次线程中不就行了 这也是代码中注释掉的 moveToThread(this)所做的,去掉注释,你会发现slot在次线程中运行
main&thread:&0x13c0&thread&thread:&0x1de0&from&thread&slot_main:&0x1de0&
这可以工作,但这是 Bradley T. Hughes 强烈批判的用法。推荐的方法后面会给出。
内容导航&第 1 页: &第 2 页:
关于&&&&的更多文章
移动异构计算是相对于同构计算来说的,同构计算就是使用同一个处
既然强大的Android Studio来了,有什么理由不去用呢?
在百年老店诺基亚和我们依依惜别之后,上周我们又迎来
大家都知道iOS的发展之迅速,这对于开发者来说,无疑
越来越多的web设计师提出了移动优先的口号,而随着硬
本书主要介绍了SQL的数据库应用和开发技术,内容涉及关系数据库和SQL概述,SQL环境,SQL对于数据表的操作,数据库查询知识,SQL
Windows Phone专家
Android开发专家
51CTO旗下网站22644人阅读
QT编程(4)
&&&&&&& 昨晚在一个邮件列表里面看见一个关于在线程种使用signal/slot的讨论,由于回复太多,这里就不贴出原文了。
&&&&&&& 主要是关于怎样从一个线程发送信号到另外一个线程的问题。其实这个也不是什么复杂的问题,在qt的asstant里面已经描诉的比较清楚了。当我们链接信号的时候使用qt::queuedConnection就能使slot在它自己的线程里面运行。
&&&&&&& 另我惊讶的是在其中一个的回复种他给出了一些资料,其中一个名为you‘ar doing it wrong。帖子是英文的,由于英文水平有限,加上他所说的使用QT thread的方式和我们平时直接派生QThread实现run函数的方式不一样,所以让我看的非常含糊,甚至到了不清不楚的地步。看了后面的大量的回复和讨论,勉强明白了它的意思。
&&& 具体请看这里
&&&&&& 在那里他提出了一种新的使用QThread的方式,其实也不算是信了,据说qt 4.4就已经有了。那就是QObject::moveToThread。根据QT的asstant的描述,moveToThread的作用是把一个QOject移动到一个线程里面去,那么它到底是什么意思呢。我的理解就是当我们调用QObject的moveToThread方法之后,我们这个派生自QObject的类的代码就会在新的线程里面执行。而那篇文章所说的就是大多数对这个函数产生了误解,人们总是在派生的QThread的类的构造函数里面调用moveToThread(this)以希望把该类的所有函数都在该线程里面执行。这样是错误的。
&&&&&&&& 今天为了验证这个方法到底有什么用,写了一些代码来做测试。
#include &QObject&
#include &QDebug&
#include &QThread&
class MyObject : public QObject {
MyObject() {};
~MyObject() {}
public slots:
void first() {
qDebug() && QThread::currentThreadId();
void second() {
qDebug() && QThread::currentThreadId();
void three() {
qDebug() && QThread::currentThreadId();
2、mainwindow.cxx
#include &mainwindow.h&
#include &QPushButton&
#include &QVBoxLayout&
#include &myobject.h&
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
my = new MyO
firstButton = new QPushButton(tr(&first&), 0);
connect(firstButton, SIGNAL(clicked()), my, SLOT(first()), Qt::QueuedConnection);
secondButton = new QPushButton(tr(&second&), 0);
connect(secondButton, SIGNAL(clicked()), my, SLOT(second()), Qt::QueuedConnection);
threeButton = new QPushButton(tr(&three&), 0);
connect(threeButton, SIGNAL(clicked()), my, SLOT(three()), Qt::QueuedConnection);
selfButton = new QPushButton(tr(&self&), 0);
connect(selfButton, SIGNAL(clicked()), this, SLOT(onSelfPushed()));
exitButton = new QPushButton(tr(&exit&), 0);
connect(exitButton, SIGNAL(clicked()), this, SLOT(onExitPushed()));
QVBoxLayout *layout = new QVBoxL
layout-&addWidget(firstButton);
layout-&addWidget(secondButton);
layout-&addWidget(threeButton);
layout-&addWidget(selfButton);
layout-&addWidget(exitButton);
QWidget *p = new QW
p-&setLayout(layout);
QThread *thread = new QT
my-&moveToThread(thread);
thread-&start();
connect(thread, SIGNAL(started()), my, SLOT(first()));
setCentralWidget(p);
MainWindow::~MainWindow() {
void MainWindow::onFirstPushed() {
my-&first();
void MainWindow::onSecondPushed() {
my-&second();
void MainWindow::onThreePushed() {
my-&three();
void MainWindow::onSelfPushed() {
qDebug() && QThread::currentThreadId();
void MainWindow::onExitPushed() {
&&& 通过测试,在mainwidow.cxx使用上面的代码的时候,由于my调用了movetothread函数,那么它所有的槽函数都是执行在新开辟的线程里面。
&& 如果去掉moveToThread函数,那么所有的函数都将执行在gui线程里面。
&& 同时为了测试connect的第五个参数,在connect的时候可以将Qt::QueuedConnection修改为Qt::DirectConnection,这样所有的槽函数也将在主线程里面执行。
&&&& 最后要注意的是,如果上面connect的时候连接的是this的onXXXXXX槽函数再来调用的my的槽函数的话,那么这些槽函数也将执行在onXXXXX槽函数所在的线程,这里是主线程。
&&&& 通过上面的测试,我们在使用线程的时候,就可以将一个类派生自QObject,然后实现所有的signal/slot,然后通过调用movetothread函数来使他们执行在新的线程里面,而不是每次都要重新派生QThread,并且派生QThread函数的另外一个不好的地方是只有run函数内部的代码才会执行在新线程里面,相比起来,派生QObject并使用movetothread函数更具有灵活性。
&&& 最后,把讨论中列出的所有的网址列出来哈。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:96790次
积分:1289
积分:1289
排名:千里之外
原创:29篇
转载:13篇
评论:32条
(1)(2)(2)(1)(5)(2)(1)(4)(1)(1)(3)(2)(10)(7)c++ - qt thread with movetothread - Stack Overflow
to customize your list.
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.
J it only takes a minute:
Join the Stack Overflow community to:
Ask programming questions
Answer and help your peers
Get recognized for your expertise
I'm trying to create a program using threads:
the main start with a loop.
When a test returns true, I create an object and I want
that object to work in an other thread
then return and start the test .
QCoreApplication a(argc, argv);
while(true){
cmd =db-&select(cmd);
if(cmd.isNull()){
QThread *thread = new QThread( );
process *class= new process ();
class-&moveToThread(thread);
thread-&start();
qDebug() && " msg"; // this doesn't run until
class finish it's work
return a.exec();
the problem is when i start the new thread the main thread stops and wait for the new thread's finish .
The canonical Qt way would look like this:
QThread *thread = new QThread( );
= new Task();
task-&moveToThread(thread);
connect( thread, SIGNAL(started()), task, SLOT(doWork()) );
connect( task, SIGNAL(workFinished()), thread, SLOT(quit()) );
//automatically delete thread and task object when work is done:
connect( thread, SIGNAL(finished()), task, SLOT(deleteLater()) );
connect( thread, SIGNAL(finished()), thread, SLOT(deleteLater()) );
thread-&start();
in case you arent familiar with signals/slots, the Task class would look something like this:
class Task : public QObject
public slots:
void doWork();
void workFinished();
34.7k17100126
3,76712043
I don't know how you structured your process class, but this is not really the way that moveToThread works.
The moveToThread function tells QT that any slots need to be executed in the new thread rather than in the thread they were signaled from. (edit: Actually, I now remember it defaults to the tread the object was created in)
Also, if you do the work in your process class from the constructor it will not run in the new thread either.
The simplest way to have your process class execute in a new thread is to derive it from QThread and override the run method.
Then you never need to call move to thread at all.
Your Answer
Sign up or
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Post as a guest
By posting your answer, you agree to the
Not the answer you're looking for?
Browse other questions tagged
Stack Overflow works best with JavaScript enabled

我要回帖

更多关于 qt movetothread 用法 的文章

 

随机推荐