[英]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.