What happens to the thread affinity of a QObject created within a worker thread which then terminates?

后端 未结 6 856
庸人自扰
庸人自扰 2021-02-05 04:39

Let\'s say I call QtConcurrent::run() which runs a function in a worker thread, and in that function I dynamically allocate several QObjects (for later use). Since

6条回答
  •  眼角桃花
    2021-02-05 05:20

    Does Qt automatically move the QObjects into the parent thread, or are we responsible in moving them to a valid thread before the worker thread terminates?

    No, Qt doesn't automatically move QObject into the parent thread.

    This behavior doesn't explicitly documented, so I've done a small investigation of the Qt framework source code, master branch.

    QThread starts in QThreadPrivate::start:

    unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(void *arg)
    {
    
      ...
    
      thr->run();
    
      finish(arg);
      return 0;
    }
    

    QThread::terminate() implementation:

    void QThread::terminate()
    {
      Q_D(QThread);
      QMutexLocker locker(&d->mutex);
      if (!d->running)
          return;
      if (!d->terminationEnabled) {
          d->terminatePending = true;
          return;
      }
      TerminateThread(d->handle, 0);
      d->terminated = true;
      QThreadPrivate::finish(this, false);
    }
    

    In both cases thread finalization is done in QThreadPrivate::finish:

    void QThreadPrivate::finish(void *arg, bool lockAnyway)
    {
      QThread *thr = reinterpret_cast(arg);
      QThreadPrivate *d = thr->d_func();
    
      QMutexLocker locker(lockAnyway ? &d->mutex : 0);
      d->isInFinish = true;
      d->priority = QThread::InheritPriority;
      bool terminated = d->terminated;
      void **tls_data = reinterpret_cast(&d->data->tls);
      locker.unlock();
      if (terminated)
          emit thr->terminated();
      emit thr->finished();
      QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
      QThreadStorageData::finish(tls_data);
      locker.relock();
    
      d->terminated = false;
    
      QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher;
      if (eventDispatcher) {
          d->data->eventDispatcher = 0;
          locker.unlock();
          eventDispatcher->closingDown();
          delete eventDispatcher;
          locker.relock();
      }
    
      d->running = false;
      d->finished = true;
      d->isInFinish = false;
    
      if (!d->waiters) {
          CloseHandle(d->handle);
          d->handle = 0;
      }
    
      d->id = 0;
    }
    

    It posts QEvent::DeferredDelete event to cleanup QObject::deleteLater, than TLS data cleaned up with QThreadStorageData::finish(tls_data) and eventDispatcher deleted. After that QObject will receive no events from this thread, but QObject's thread affinity stays the same. It's interesting to see implementation of void QObject::moveToThread(QThread *targetThread) to understand how thread affinity changes.

    Implementation of void QThreadPrivate::finish(void *arg, bool lockAnyway) makes clear that QObject's thread affinity is not changed by QThread.

提交回复
热议问题