简体   繁体   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();}

I have the following setup:我有以下设置:

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();
}

The idea is that I have the DBManager which is doing asynchronous database accesses and hence it utilized throughout the entire application.这个想法是我有 DBManager,它正在执行异步数据库访问,因此它在整个应用程序中使用。 During the initialization of the application I need to retrieve some information from the database and I'd like to use the already existing DBManager for that.在应用程序的初始化期间,我需要从数据库中检索一些信息,我想为此使用现有的 DBManager。

However, since I need the information from the database to create all other objects, I want to block the futher execution of the main thread until my InitHelper has retrieved all required information from the DBManager.但是,由于我需要来自数据库的信息来创建所有其他对象,所以我想阻止主线程的进一步执行,直到我的 InitHelper 从 DBManager 检索到所有必需的信息。

Since the code above does exactly what it is supposed to, I don't think it matters how exactly InitHelper and DBManager are implemented and I have omitted them here.由于上面的代码完全符合它的预期,我认为 InitHelper 和 DBManager 的实现方式并不重要,我在这里省略了它们。

What I find confusing is the fact that I need to use the lambda in the second line in the 'wire InitHelper and its thread' part.我发现令人困惑的是,我需要在“wire InitHelper 及其线程”部分的第二行中使用 lambda。 If I replace如果我更换

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

by经过

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

apparently the thread never shuts down and so "Initialization completed" will never be print to stdout.显然线程永远不会关闭,因此“初始化完成”永远不会打印到标准输出。

This is the output when using the connection to the lambda:这是使用与 lambda 的连接时的输出:

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

whereas when connecting to the slot directly, I get this output:而当直接连接到插槽时,我得到以下输出:

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

Does someone know why there is a difference when connecting to the lambda instead of connecting to the slot directly?有人知道为什么连接到 lambda 而不是直接连接到插槽时会有区别吗? And how can I write the connect without a lambda?我如何在没有 lambda 的情况下编写连接?

In your code:在您的代码中:

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

Is similar to:类似于:

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

It basically means that you are directly calling the function instead of using the event loop.它基本上意味着您直接调用函数而不是使用事件循环。

The reason, I believe, that your "correct" code does not work (ie when you use the Qt::QueuedConnection - which is default) is because you have not started the Qt event loop running by calling a.exec();我相信,您的“正确”代码不起作用的原因(即当您使用 Qt::QueuedConnection - 这是默认设置时)是因为您尚未通过调用a.exec();启动 Qt 事件循环运行a.exec();

To solve this, I would remove your wait() function and move your "startup" code into a startup class (a bit like your initHelper).为了解决这个问题,我将删除您的 wait() 函数并将您的“启动”代码移动到一个启动类中(有点像您的 initHelper)。 Connect a signal from the finished of your initHelper to the start() function (or whatever you want to call it) of your startup class.将来自 initHelper 的完成的信号连接到启动类的 start() 函数(或任何您想调用的函数)。

edit编辑

you might be able to do this (just read something similar):你也许能够做到这一点(只需阅读类似的内容):

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