movetothread
moveToThread对比传统子类化Qthread更灵活,仅需要把你想要执行的代码放到槽,movetothread这个object到线程,然后拿一个信号连接到这个槽就可以让这个槽函数在线程里执行。可以说,movetothread给我们编写代码提供了新的思路,当然不是说子类化qthread不好,只是你应该知道还有这种方式去调用线程。
老大认为,轻量级的函数可以用movethread,多个短小精悍能返回快速的线程函数适用 ,无需创建独立线程类,例如你有20个小函数要在线程内做, 全部扔给一个QThread。而我觉得movetothread和子类化QThread的区别不大,更可能是使用习惯引导。又或者你一开始没使用线程,但是后边发觉这些代码还是放线程比较好,如果用子类化QThread的方法重新设计代码,将会有可能让你把这一段推到重来,这个时候,moveThread的好处就来了,你可以把这段代码的从属着movetothread,把代码移到槽函数,用信号触发它就行了。其它的话movetothread它的效果和子类化QThread的效果是一样的,槽就相当于你的run()函数,你往run()里塞什么代码,就可以往槽里塞什么代码,子类化QThread的线程只可以有一个入口就是run(),而movetothread就有很多触发的入口。
|
Constant |
Value |
Description |
|
QThread::IdlePriority |
0 |
没有其它线程运行时才调度. |
|
QThread::LowestPriority |
1 |
比LowPriority调度频率低. |
|
QThread::LowPriority |
2 |
比NormalPriority调度频率低. |
|
QThread::NormalPriority |
3 |
操作系统默认的默认优先级. |
|
QThread::HighPriority |
4 |
比NormalPriority调度频繁. |
|
QThread::HighestPriority |
5 |
比HighPriority调度频繁. |
|
QThread::TimeCriticalPriority |
6 |
尽可能频繁的调度. |
|
QThread::InheritPriority |
7 |
使用和创建线程同样的优先级. 这是默认值. |
在Qt之线程(QThread)一节中我介绍了QThread 的两种使用方法:
1、子类化 QThread(不使用事件循环)。
这是官方手册、例子以及相关书籍中都介绍的一种常用的方法。
a. 子类化 QThread
b. 重载 run 函数,run函数内有一个while或for的死循环(模拟耗时操作)
c. 设置一个标记为来控制死循环的退出。
2、子类化 QObject
a. 子类化 QObject
b. 定义槽函数
c. 将该子类的对象moveToThread到新线程中
run 对于线程的作用相当于main函数对于应用程序。它是线程的入口,run的开始和结束意味着线程的开始和结束。
采用这两种做法,毫无疑问都会在次线程中运行(这里说的是,run中的逻辑以及子类化QObject后连接通过moveToThread然后连接到QThread的started()信号的槽函数,这个下面会详细讲解)。
那么,线程中的槽函数是怎么运行的呢?
说到信号与槽,大家应该再熟悉不过了,包括我,特别喜欢使用自定义信号与槽,感觉用起来特方便、特棒。。。
经常使用,你能否100%的使用正确?你了解它的高级用法吗?
1、你是否在多次connect,还发现不了为什么槽函数会执行那N多次。
2、你是否了解disconnect
3、你是否了解connect中的第五个参数 Qt::ConnectionType
关于connect、disconnect信号、槽的使用可参考:Qt之信号与槽。既然谈到线程这里需要重点说下Qt::ConnectionType(信号与槽的传递方式)
|
Constant |
Value |
Description |
|
Qt::AutoConnection |
0 |
自动连接:(默认值)如果信号在接收者所依附的线程内发射,则等同于直接连接。如果发射信号的线程和接受者所依附的线程不同,则等同于队列连接。 |
|
Qt::DirectConnection |
1 |
直接连接:当信号发射时,槽函数将直接被调用。无论槽函数所属对象在哪个线程,槽函数都在发射信号的线程内执行。 |
|
Qt::QueuedConnection |
2 |
队列连接:当控制权回到接受者所依附线程的事件循环时,槽函数被调用。槽函数在接收者所依附线程执行。也就是说:这种方式既可以在线程内传递消息,也可以跨线程传递消息 |
|
Qt::BlockingQueuedConnection |
3 |
与Qt::QueuedConnection类似,但是会阻塞等到关联的slot都被执行。这里出现了阻塞这个词,说明它是专门用来多线程间传递消息的。 |
举例:
MyObject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject *parent = 0);
public slots:
void start();
};
#endif // MYOBJECT_H
// MYOBJECT_H
MyObject.cpp
#include "MyObject.h"
#include
#include
MyObject::MyObject(QObject *parent)
: QObject(parent)
{
}
void MyObject::start()
{
qDebug() << QString("my object thread id:") << QThread::currentThreadId();
}
#include "MyObject.h"
#include
#include
MyObject::MyObject(QObject *parent)
: QObject(parent)
{
}
void MyObject::start()
{
qDebug() << QString("my object thread id:") << QThread::currentThreadId();
}
main.cpp
#include "MyObject.h"
#include
#include
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug() << QString("main thread id:") << QThread::currentThreadId();
MyObject object;
QThread thread;
object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()));
thread.start();
return a.exec();
}
#include "MyObject.h"
#include
#include
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug() << QString("main thread id:") << QThread::currentThreadId();
MyObject object;
QThread thread;
object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()));
thread.start();
return a.exec();
}
"main thread id:" 0xf08
"my object thread id:" 0x216c
显然主线程与槽函数的线程是不同的(你可以多次尝试,屡试不爽。。。),因为moveToThread后MyObject所在的线程为QThread,继上面介绍的thread.start()执行后首先会发射started()信号,也就是说started()信号发射是在次线程中进行的,所以无论采取Qt::AutoConnection、Qt::DirectConnection、Qt::QueuedConnection哪种连接方式,主线程与槽函数的线程都是不同的。
1、修改代码如下:
MyObject object;
QThread thread;
//object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::DirectConnection);
thread.start();
MyObject object;
QThread thread;
//object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::DirectConnection);
thread.start();
"main thread id:" 0x2688
"my object thread id:" 0x2110
显然主线程与槽函数的线程是不同的,MyObject所依附的线程为主线程(因为注释掉了moveToThread),继上面介绍的Qt::DirectConnection(无论槽函数所属对象在哪个线程,槽函数都在发射信号的线程内执行)。也就是说started()信号发射是在次线程中进行的,槽函数也是在次线程中进行的,所以主线程与槽函数的线程是不同的。
2、修改代码如下:
MyObject object;
QThread thread;
//object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::QueuedConnection);
thread.start();
MyObject ob
ject;
QThread thread;
//object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::QueuedConnection);
thread.start();
查看运行结果:
"main thread id:" 0x24ec
"my object thread id:" 0x24ec
显然主线程与槽函数的线程是相同的,继上面介绍的Qt::QueuedConnection(槽函数在接收者所依附线程执行)。也就是说started()信号发射是在次线程中进行的,但MyObject所依附的线程为主线程(因为注释掉了moveToThread),所以主线程与槽函数的线程必然是相同的。
3、修改代码如下:
MyObject object;
QThread thread;
//object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::AutoConnection);
thread.start();
MyObject object;
QThread thread;
//object.moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), &object, SLOT(start()), Qt::AutoConnection);
thread.start();
"main thread id:" 0x2700
"my object thread id:" 0x2700
显然主线程与槽函数的线程是相同的,MyObject所依附的线程为主线程(因为注释掉了moveToThread),继上面介绍的Qt::AutoConnection(如果信号在接收者所依附的线程内发射,则等同于直接连接。如果发射信号的线程和接受者所依附的线程不同,则等同于队列连接。)。因为started()信号和MyObject依附的线程不同,所以结果和Qt::QueuedConnection对应的相同,所以主线程与槽函数的线程是相同的。
基本就介绍到这里,QThread使用和上面的大同小异,run里面执行的代码都是在次线程中,如果是QThead的槽函数,那么结论同上!
浙公网安备 33010602011771号