簡體   English   中英

QThread 線程間通信:連接到 &QThread::quit 與連接到 lambda [&thread] { thread->quit();} 的奇怪行為

[英]QThread interthread communication: strange behavior connecting to &QThread::quit vs connecting to a lambda [&thread] { thread->quit();}

我有以下設置:

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // Create the DBManager that will live for the entire
    // duration of the application
    auto dbManagerThread = std::make_unique<QThread>();
    auto dbManager = std::make_unique<DBManager>();
    dbManager->moveToThread(dbManagerThread.get());
    dbManagerThread->start();


    // for the initialization of the application, create the
    // InitHelper object that will utilize the DBManager
    auto initHelper = new InitHelper();
    auto initHelperThread = new QThread();
    initHelper -> moveToThread(initHelperThread);
    // wire InitHelper and its thread
    QObject::connect(initHelperThread, &QThread::started, initHelper, &InitHelper::run);
    QObject::connect(initHelper, &InitHelper::finished, [&initHelperThread] { initHelperThread->quit();});
    QObject::connect(initHelper, &InitHelper::finished, initHelper, &InitHelper::deleteLater);
    QObject::connect(initHelperThread, &QThread::finished, initHelperThread, &QThread::deleteLater);

    // wire InitHelper and DBManager
    QObject::connect(initHelper, &InitHelper::queryDB, dbManager.get(), &DBManager::processQuery);
    QObject::connect(dbManager.get(), &DBManager::queryResult, initHelper, &InitHelper::processQueryResult);


    // block until all information is gathered
    initHelperThread->start();
    initHelperThread->wait();
    std::cout << "Initialization completed." << std::endl;

    // cleanup
    dbManagerThread->quit();
    QObject::connect(dbManagerThread.get(), &QThread::finished, &a, &QCoreApplication::quit);
    return a.exec();
}

這個想法是我有 DBManager,它正在執行異步數據庫訪問,因此它在整個應用程序中使用。 在應用程序的初始化期間,我需要從數據庫中檢索一些信息,我想為此使用現有的 DBManager。

但是,由於我需要來自數據庫的信息來創建所有其他對象,所以我想阻止主線程的進一步執行,直到我的 InitHelper 從 DBManager 檢索到所有必需的信息。

由於上面的代碼完全符合它的預期,我認為 InitHelper 和 DBManager 的實現方式並不重要,我在這里省略了它們。

我發現令人困惑的是,我需要在“wire InitHelper 及其線程”部分的第二行中使用 lambda。 如果我更換

QObject::connect(initHelper, &InitHelper::finished, [&initHelperThread] { initHelperThread->quit();});

經過

QObject::connect(initHelper, &InitHelper::finished, initHelperThread, &QThread::quit);

顯然線程永遠不會關閉,因此“初始化完成”永遠不會打印到標准輸出。

這是使用與 lambda 的連接時的輸出:

InitHelper: Initialization started...
DBManager: processing query...
InitHelper: processing query result
Initialization completed.

而當直接連接到插槽時,我得到以下輸出:

InitHelper: Initialization started...
DBManager: processing query...
InitHelper: processing query result

有人知道為什么連接到 lambda 而不是直接連接到插槽時會有區別嗎? 我如何在沒有 lambda 的情況下編寫連接?

在您的代碼中:

QObject::connect(initHelper, &InitHelper::finished, [&initHelperThread] { initHelperThread->quit();});

類似於:

QObject::connect(initHelper, &InitHelper::finished, initHelperThread, &QThread::quit, Qt::DirectConnection);

它基本上意味着您直接調用函數而不是使用事件循環。

我相信,您的“正確”代碼不起作用的原因(即當您使用 Qt::QueuedConnection - 這是默認設置時)是因為您尚未通過調用a.exec();啟動 Qt 事件循環運行a.exec();

為了解決這個問題,我將刪除您的 wait() 函數並將您的“啟動”代碼移動到一個啟動類中(有點像您的 initHelper)。 將來自 initHelper 的完成的信號連接到啟動類的 start() 函數(或任何您想調用的函數)。

編輯

你也許能夠做到這一點(只需閱讀類似的內容):

int ret = a.exec();
initHelperThread->wait();
std::cout << "Initialization completed." << std::endl;
    :
  do other stuff
    :
return ret;

暫無
暫無

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

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