返回对象所在的线程。
QThread *QObject::thread() const
{
return d_func()->threadData.loadRelaxed()->thread.loadAcquire();
}
将此对象及其孩子关联到targetThread线程,事件处理将在targetThread中继续进行,
在线程关联被改变之前QEvent::ThreadChange事件被发送给这个对象和其孩子对象。
注意:
使用样例:
int main()
{
QThread *th = new QThread();
myobject *obj1= new myobject("boj1");
obj1->connect(obj1,&myobject::signal1,obj1,&myobject::slot1);
obj1->moveToThread(th);//调用在主线程与obj1同一线程
//因为线程启动后才会执行事件循环,所以必须启动线程
th->start();
qDebug()<<"main QThreadid = "<<QThread::currentThreadId()<<",date="<<QDateTime::currentSecsSinceEpoch();
emit obj1->signal1(111);
return 0;
}
函数解读:
void QObject::moveToThread(QThread *targetThread)
{
Q_D(QObject);
//如果对象有父对象,则不能移动该对象。
if (d->parent != nullptr) {
qWarning("QObject::moveToThread: Cannot move objects with a parent");
return;
}
//对象是widget类型的不能移动widget类型的只能在主线程中
//继承QWidget的类都是widget类型
//explicit QWidget(QWidget* parent = nullptr, Qt::WindowFlags);
if (d->isWidget) {
qWarning("QObject::moveToThread: Widgets cannot be moved to a new thread");
return;
}
//调用此函数的所在线程,即当前线程
QThreadData *currentData = QThreadData::current();
//移动到的目标线程
QThreadData *targetData = targetThread ? QThreadData::get2(targetThread) : nullptr;
//对象所在线程数据,
QThreadData *thisThreadData = d->threadData.loadRelaxed();
//如果对象没有关联线程,并且目标线程等于当前线程,可以移动
if (!thisThreadData->thread.loadAcquire() && currentData == targetData)
{
//我们允许将没有线程关联的对象移动到当前线程
currentData = d->threadData;
} else if (thisThreadData != currentData) {
//只能在object所在的线程里面调用此函数
qWarning("QObject::moveToThread: Current thread (%p) is not the object's thread (%p).\n"
"Cannot move to target thread (%p)\n",
currentData->thread.loadRelaxed(), thisThreadData->thread.loadRelaxed(), targetData ? targetData->thread.loadRelaxed() : nullptr);
return;
}
// 移动前先发送QEvent::ThreadChange事件
d->moveToThread_helper();
if (!targetData)
targetData = new QThreadData(0);
//确保在我们移动这个对象时没有人添加/删除连接
QMutexLocker l(signalSlotLock(this));
QOrderedMutexLocker locker(¤tData->postEventList.mutex,
&targetData->postEventList.mutex);
// 保持currentData存活(因为我们已经锁定了它)
currentData->ref();
// 真正的移动对象
d_func()->setThreadData_helper(currentData, targetData);
locker.unlock();
// now currentData can commit suicide if it wants to
currentData->deref();
}
void QObjectPrivate::moveToThread_helper()
{
Q_Q(QObject);
QEvent e(QEvent::ThreadChange);
//sendEvent发送ThreadChange事件
//因为sendEvent是同步调用,所以等对象处理完事件后,才能继续往下走
QCoreApplication::sendEvent(q, &e);
//给对象的所有孩子发送ThreadChange事件
for (int i = 0; i < children.size(); ++i) {
QObject *child = children.at(i);
child->d_func()->moveToThread_helper();
}
}
void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData *targetData)
{
for (int i = 0; i < currentData->postEventList.size(); ++i) {
const QPostEvent &pe = currentData->postEventList.at(i);
if (!pe.event)
continue;
if (pe.receiver == q) {
//将此post事件移动到targetList中
targetData->postEventList.addEvent(pe);
const_cast<QPostEvent &>(pe).event = nullptr;
++eventsMoved;
}
}
//当前线程在调用moveToThread()后不应该恢复currentSender
ConnectionData *cd = connections.loadRelaxed();
if (cd) {
if (cd->currentSender) {
cd->currentSender->receiverDeleted();
cd->currentSender = nullptr;
}
// 调整连接中的receiverThreadId值
if (cd) {
auto *c = cd->senders;
while (c) {
QObject *r = c->receiver.loadRelaxed();
if (r) {
Q_ASSERT(r == q);
targetData->ref();
QThreadData *old = c->receiverThreadData.loadRelaxed();
if (old)
old->deref();
c->receiverThreadData.storeRelaxed(targetData);
}
c = c->next;
}
}
}
// 设置新线程数据
targetData->ref();
threadData.loadRelaxed()->deref();
//同步其孩子到targetData线程
//QObject的孩子肯定不是widget一类,所以可以直接移动不用判断
for (int i = 0; i < children.size(); ++i) {
QObject *child = children.at(i);
child->d_func()->setThreadData_helper(currentData, targetData);
}
}