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

后端 未结 6 773
庸人自扰
庸人自扰 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:32

    QThread is not documented to automatically move any QObjects when it finishes, so I think we can already conclude that it does no such thing. Such behavior would be very surprising, and at odds with the rest of the API.

    Just for completeness, I tested with Qt 5.6:

    QObject o;
    {
        QThread t;
        o.moveToThread(&t);
        for (int i = 0; i < 2; ++i)
        {
            t.start();
            QVERIFY(t.isRunning());
            QVERIFY(o.thread() == &t);
            t.quit();
            t.wait();
            QVERIFY(t.isFinished());
            QVERIFY(o.thread() == &t);
        }
    }
    QVERIFY(o.thread() == nullptr);
    

    Recall that a QThread is not a thread, it manages a thread.

    When a QThread finishes, it continues to exist, and the objects that live in it continue to live in it, but they no longer process events. The QThread can be restarted (not recommended), at which point event processing will resume (so the same QThread could then be managing a different thread).

    When a QThread is destroyed, the objects that lived in it cease to have any thread affinity. The documentation doesn't guarantee this, and in fact says "You must ensure that all objects created in a thread are deleted before you delete the QThread."


    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 they were created in the worker thread, their thread affinity should be that of the worker thread. However, once the worker thread terminates, the QObject thread affinity should no longer be valid.

    The QThread does not terminate in this scenario. When a task spawned by QtConcurrent::run finishes, the QThread it was running in is returned to the QThreadPool and may be reused by a subsequent call to QtConcurrent::run, and QObjects living in that QThread continue to live there.

    QThreadPool::globalInstance()->setMaxThreadCount(1);
    QObject *o = nullptr;
    QThread *t = nullptr;
    QFuture f = QtConcurrent::run([&] {
        o = new QObject;
        t = o->thread();
        QVERIFY(t == QThread::currentThread());
    });
    f.waitForFinished();
    QVERIFY(t == o->thread());
    QVERIFY(t->isRunning());
    f = QtConcurrent::run([=] {
        QVERIFY(t == QThread::currentThread());
    });
    f.waitForFinished();
    

    You might want to manually move an object out of a QThread before it is returned to the QThreadPool, or just don't use QtConcurrent::run. Having a QtConcurrent::run task construct QObjects which outlive the task is a questionable design, tasks should be self-contained. As noted by @Mike, the QThreads used by QtConcurrent::run do not have event loops.

提交回复
热议问题