分析
官网的说明:
void QObject::moveToThread(QThread *targetThread)
Changes the thread affinity for this object and its children. The
object cannot be moved if it has a parent. Event processing will
continue in the targetThread.To move an object to the main thread, use QApplication::instance() to
retrieve a pointer to the current application, and then use
QApplication::thread() to retrieve the thread in which the application
lives. For example:myObject->moveToThread(QApplication::instance()->thread());
If targetThread is zero, all event processing for this object and its
children stops.Note that all active timers for the object will be reset. The timers
are first stopped in the current thread and restarted (with the same
interval) in the targetThread. As a result, constantly moving an
object between threads can postpone timer events indefinitely.A QEvent::ThreadChange event is sent to this object just before the
thread affinity is changed. You can handle this event to perform any
special processing. Note that any new events that are posted to this
object will be handled in the targetThread.Warning: This function is not thread-safe; the current thread must be
same as the current thread affinity. In other words, this function can
only “push” an object from the current thread to another thread, it
cannot “pull” an object from any arbitrary thread to the current
thread.
其中关键的一句话:
Changes the thread affinity for this object and its children. The
object cannot be moved if it has a parent. Event processing will
continue in the targetThread.
这一句话的理解:
1、对象的构造函数不但不能用父类,父类的其它东西也是不行的
2、改变线程的关联,针对对象和它的孩子们,但是,如果不是孩子的new是不行的
示例1
改变线程的关联,针对对象和它的孩子们,但是,如果不是孩子的new是不行的。
如下图所示:
对象里面单独的new的变量是移不到目标线程当中去的,除非是作为孩子的节点。
controll的代码:
#include "controller.h"
Controller::Controller(QObject *parent) : QObject(parent)
{
QString name = "thread1";
Worker *worker = new Worker(name);
m_pWorkerThread = new QThread();
worker->moveToThread(m_pWorkerThread);
connect(m_pWorkerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(this, &Controller::signalsBegin, worker, &Worker::onBegin);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
m_pWorkerThread->start();
}
Controller::~Controller()
{
m_pWorkerThread->quit();
m_pWorkerThread->wait();
}
void Controller::beginOperate()
{
QString str = "begin";
emit operate(str);
}
void Controller::begin()
{
emit signalsBegin();
}
void Controller::handleResults(const QString &str)
{
qDebug("enter function Controller::handleResults str=%s", str.toStdString().c_str());
QThread *currentThread = QThread::currentThread();
qDebug("exit function Controller::handleResults currentThread=%p", currentThread);
}
worker类的代码:
Worker::Worker(QString name, QObject *parent) : QObject(parent)
{
qDebug("name=%s", name.toStdString().c_str());
m_name = name;
m_pTimer = new QTimer();
m_pTimer->setInterval(1000);
}
void Worker::doWork(const QString ¶meter)
{
qDebug("enter function Worker::doWork parameter=%s", parameter.toStdString().c_str());
QString result;
/* ... here is the expensive or blocking operation ... */
result = "executing";
emit resultReady(result);
QThread *currentThread = QThread::currentThread();
qDebug("exit function Worker::doWork currentThread=%p", currentThread);
}
void Worker::onBegin()
{
m_pTimer->start();
}
主函数:
#include <QCoreApplication>
#include "controller.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Controller *controller = new Controller();
controller->beginOperate();
controller->begin();
return a.exec();
}
上面的问题就是:
controller->begin()这一句导致的问题,这一句调用了:m_pTimer->start();
而成员变量m_pTimer是在主线程创建的,而非在子线程创建的,所以报上面的错。
由此可见:movetoThread()函数,只是移动了非new的成员变量与子对象,也就是未移动非子对象的new变量。
代码更改如下就可以了:
Worker::Worker(QString name, QObject *parent) : QObject(parent)
{
qDebug("name=%s", name.toStdString().c_str());
m_name = name;
m_pTimer = new QTimer(this);
m_pTimer->setInterval(1000);
}
就是QTimer()改成了QTimer(this);
总结
这个东西怎么说呢?movetoThread()函数,只是移动了非new的成员变量与子对象,也就是未移动非子对象的new变量,在QT中变量不能跨线程,所以跨线程的变量都会报错,有的报:
Cannot create children for a parent that is in a different thread.
这一个错误不需要加this,因为,this是主线程的this,去掉this即可解决问题。
QObject::startTimer: Timers cannot be started from another thread
这一个错误,需要加this,因为this是目标线程的this,加了this,Timers也移到目标线程了,这样就在一个线程中了。
其本质是一样的就是,变量跨线程(父与子跨线程也是不允许的,实质也是变量跨线程)
未moveToThread时是这样:
moveToThread之后是这样: