簡體   English   中英

QThread::create 在 UI 線程上運行

[英]QThread::create running on UI Thread

我的應用程序需要多線程。 根據 Qt 的文檔,有很多方法可以實現這一點。

簡要概述QThread ing方法:

  1. 子類 QThread 並重新實現 run() ( doc )。

  2. 創建一個 object 繼承自QObject並使用Q_OBJECT宏(用於信號/插槽)和doWork方法,創建一個QThread object,使用QObject::moveToThread(QThread*)並調用QThread::start()文檔維基

  3. 對 lambda 語法使用QThread::create(Function &&f)QThread::create(std::function<>)

我選擇使用第三個選項進行測試。 我還基於選項 2 實現了一個名為QThreading的多線程庫,使用QWorkerThread充當 controller object, QThreadQObject作為對象。 這個庫也給出了相同的結果,如下所示。


既然文檔已經不在了,問題就來了。

使用QThread::create(Function &&f) ,我正在測試 QThread 是否與 UI 線程分開運行。 下面的MCVE示例:

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qsrand(0);
    QThread *thread = nullptr;
    auto threadTest = std::function<void ()> ([&]() {

        if(thread->thread() == a.thread()) {
            qDebug() << "UI Thread in use";
        } else {
            qDebug() << "Worker thread in use";
        }

        for (int var = 0; var < INT_MAX; ++var) {
            int r = qrand() % 100;
            thread->thread()->msleep(r);
            qDebug() << "[Worker Thread " << thread->thread()->currentThreadId() << "] " << r;
        }
    });
    thread = QThread::create(threadTest);
    thread->start();

    for (int var = 0; var < INT_MAX; ++var) {
        // sleep thread 0-100ms
        int r = qrand() % 100;
        a.thread()->msleep(r);
        qDebug() << "[UI Thread " << a.thread()->currentThreadId() << "] " << r;
    }

    return a.exec();
}

output 是:

UI Thread in use
[Worker Thread  0x47e4 ]  41
[UI Thread  0x10c0 ]  38
[UI Thread  0x10c0 ]  19
[UI Thread  0x10c0 ]  38
[Worker Thread  0x47e4 ]  67
[UI Thread  0x10c0 ]  37
[Worker Thread  0x47e4 ]  34
[Worker Thread  0x47e4 ]  0
[UI Thread  0x10c0 ]  55
[Worker Thread  0x47e4 ]  69
[Worker Thread  0x47e4 ]  24
[UI Thread  0x10c0 ]  97
[Worker Thread  0x47e4 ]  78
[UI Thread  0x10c0 ]  65
[Worker Thread  0x47e4 ]  58
[UI Thread  0x10c0 ]  85
[Worker Thread  0x47e4 ]  62
[UI Thread  0x10c0 ]  50
[Worker Thread  0x47e4 ]  64
[UI Thread  0x10c0 ]  12
[Worker Thread  0x47e4 ]  5
[Worker Thread  0x47e4 ]  45

注意事項

  • UI 線程 ID: 0x10c0

  • 工作線程 ID: 0x47e4

擔憂來自哪里

正在使用的 UI 線程

讓我困惑的是不同的線程地址,但工作線程仍然等於UI 線程。

這讓我有兩種解釋:

  1. QThread::currentThread總是返回主機/主線程(難以置信,使得 function 有點毫無意義

  2. QThread *thread位於主 UI 線程內,因此(獲取父線程)始終返回父線程,即ParentThread == WorkerThread (ParentThread)

我是否想了解QThread的工作原理?

  1. 如果您想知道它是否在主線程中運行,那么您應該將 currentThread 與 QCoreApplication 線程進行比較:
if(QCoreApplication::instance()->thread() == QThread::currentThread()) {
    qDebug() << "UI Thread in use";
} else {
    qDebug() << "Worker thread in use";
}
  1. 正如文檔指出的那樣,QThread 不是線程是線程處理程序:

詳細說明

QThread object 管理程序中的一個控制線程。 QThreads 在run()中開始執行。 默認情況下,run() 通過調用 exec() 啟動事件循環,並在線程內運行 Qt 事件循環。

此外,QThread 是一個 QObject ,它存在於父線程中,或者如果它沒有父線程,則它被創建的地方,正如文檔指出的那樣:

線程親和力

QObject 實例被稱為具有線程親和性,或者說它存在於某個線程中。 當 QObject 接收到排隊的信號或發布的事件時,槽或事件處理程序將在 object 所在的線程中運行。

注意:如果 QObject 沒有線程關聯(即,如果 thread() 返回零),或者如果它存在於沒有運行事件循環的線程中,則它無法接收排隊信號或發布的事件。

默認情況下,QObject 存在於創建它的線程中。 可以使用 thread() 查詢對象的線程親和性,並使用 moveToThread() 更改對象的線程親和性。

所有 QObject 必須與其父對象存在於同一線程中。 最后:

  • 如果涉及的兩個 QObject 存在於不同的線程中,setParent() 將失敗。
  • 當一個 QObject 被移動到另一個線程時,它的所有子對象也將被自動移動。
  • 如果 QObject 有父對象,則 moveToThread() 將失敗。
  • 如果 QObjects 在 QThread::run() 中創建,它們不能成為 QThread object 的子級,因為 QThread 不存在於調用 QThread::run() 的線程中。

注意: QObject 的成員變量不會自動成為它的子變量。 必須通過將指針傳遞給子構造函數或調用 setParent() 來設置父子關系。 如果沒有這一步,調用 moveToThread() 時對象的成員變量將保留在舊線程中。

在您的情況下,“線程” object 是一個 QObject ,它存在於主線程中,因為它沒有父線程並且在那里創建並處理另一個線程。

更新:

MWE

#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include <QTimer>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qsrand(0);
    auto threadTest = std::function<void ()> ([&]() {
        if(QCoreApplication::instance()->thread() == QThread::currentThread()) {
            qDebug() << "UI Thread in use";
        } else {
            qDebug() << "Worker thread in use";
        }

        for (int var = 0; var < INT_MAX; ++var) {
            int r = qrand() % 100;
            QThread::msleep(r);
            qDebug() << "[Worker Thread " << QThread::currentThreadId() << "] " << r;
        }
    });
    QThread *thread = QThread::create(threadTest);
    thread->start();

    int var = 0;
    std::function<void ()> timerTest;
    timerTest = [&](){
        int r = qrand() % 100;
        qDebug() << "[UI Thread " << QThread::currentThreadId() << "] " << r;
        ++var;
        if (var < INT_MAX)
            QTimer::singleShot(r, timerTest);
    };
    int r = qrand() % 100;
    QTimer::singleShot(r, timerTest);

    return a.exec();
}

Output:

Worker thread in use
[UI Thread  0x7fc6222993c0 ]  94
[Worker Thread  0x7fc621f62700 ]  71
[UI Thread  0x7fc6222993c0 ]  86
[Worker Thread  0x7fc621f62700 ]  94
[UI Thread  0x7fc6222993c0 ]  37
[Worker Thread  0x7fc621f62700 ]  86
...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM