Qt跨线程使用moveToThread的注意事项(Cannot move to target thread )

考虑以下场景:
主线程(Qt主事件循环)中跨线程调用某个函数func(如QtConcurrent::run),在func中又创建了另一个线程,从而将业务逻辑丢到该线程中

class CrossThreadObject(QObject *parent) : QObject(parent)
{
	Q_OBJECT
...
public slots:
	void DoSomething()
	{ 
		//线程C
		//blockinig 
	}
}

class MainThreadObject(QObject *parent) : QObject(parent)
{
	Q_OBJECT
...
	void AsyncCall()
	{
		//线程A(主线程)
		QtConcurrent::run(this, &MainThreadObject::Process);
	}
	void Process()
	{
		//线程B(QtConcurrent线程)
		thread_ = new QThread;
		worker_.moveToThread(thread_);  //此处弹出异常 QObject::moveToThread: Current thread  
										//(0xAAAAAA) is not the object's thread (0xCCCCCC). 
										//Cannot move to target thread (0xAAAAAA) 
		connect(this, &MainThreadObject::Request, &worker_, &CrossThreadObject::DoSomething);  
		while(1)
		{
			//blocking
			emit Request();
		}
	}
signals:
	void Request();
private:
	CrossThreadObject worker_;
	QThread *thread_;
}

这里的问题在于QObject对象的所属线程不一致导致moveToThread失败,worker_在线程A中创建,而moveToThread发生在线程B中。改为临时创建即可:

	void Process()
	{
		thread_ = new QThread;
		worker_ = new CrossThreadObject;
		worker_->moveToThread(thread_);  
		connect(this, &MainThreadObject::Request, worker_, &CrossThreadObject::DoSomething);  
		...
	}
	CrossThreadObject *worker_;

官方文档给出了QObject的所属线程规则:Thread Affinity

A QObject instance is said to have a thread affinity, or that it lives in a certain thread. When a QObject receives a queued signal or a posted event, the slot or event handler will run in the thread that the object lives in.
Note: If a QObject has no thread affinity (that is, if thread() returns zero), or if it lives in a thread that has no running event loop, then it cannot receive queued signals or posted events.
By default, a QObject lives in the thread in which it is created. An object’s thread affinity can be queried using thread() and changed using moveToThread().
All QObjects must live in the same thread as their parent. Consequently:
-setParent() will fail if the two QObjects involved live in different threads.
-When a QObject is moved to another thread, all its children will be automatically moved too.
-moveToThread() will fail if the QObject has a parent.
-If QObjects are created within QThread::run(), they cannot become children of the QThread object because the QThread does not live in the thread that calls QThread::run().
Note: A QObject’s member variables do not automatically become its children. The parent-child relationship must be set by either passing a pointer to the child’s constructor, or by calling setParent(). Without this step, the object’s member variables will remain in the old thread when moveToThread() is called.

QObject对象的线程归属(thread affinity),决定了该对象的事件循环运行于所属线程。对象默认属于创建这个对象的线程,可以通过moveToThread改变对象的线程归属。
QObject对象必须跟父对象同一个线程,因此具有父对象QObject对象无法通过moveToThread改变归属,换言之根对象转移线程所属也会影响所有子对象。
QObject A的成员变量并不会跟随A的线程归属。比如A被moveToThread到别的线程了,其成员变量还是属于原来的线程(创建A的线程),除非通过成员变量的构造函数或setParent设定了A为父对象。

你可能感兴趣的:(QT,qt,开发语言)