QtConcurrent在应用程序即将退出时等待完成

3

我找不到任何明确的解决方案。我使用QtConcurrent::run()创建了一个线程。当我在线程完成之前关闭应用程序时,应用程序会崩溃。我希望在所有后台线程(QtConcurrent::run())完成后再关闭应用程序。我该怎么解决这个问题?


QFuture<void> future = QtConcurrent::run(yourFunction); 然后你需要等待它完成:future.waitForFinished(); - IAmInPLS
谢谢Alexis。如果我使用future.waitForFinished(),GUI会被锁定。这必须是后台线程。当我关闭应用程序时,QtConcurrent::run()必须完成。 - Kevin yudo
然后,看看这个问题:https://dev59.com/3Gcs5IYBdhLWcg3w3HgG 当然还有它的答案。 - IAmInPLS
使用 QFutureWatcher::finished 信号。 - thuga
你将启动多少个线程?你是否在许多类中使用了QtConcurrent :: run()?也许你可以在启动线程的类的析构函数中使用future.waitForFinished() - Mike
2个回答

4

我也曾经遇到过和你一样的问题,最终我找到了自己的解决方式。以下是我的方法:

// [...] All necessary includes would go here

int main(int argc, char *argv[])
{
    // Keep track of time
    quint64 start=QDateTime::currentMSecsSinceEpoch();

    // Qt app instance
    QCoreApplication app(argc, argv);

    // Someplace safe to keep our futures
    QList<QFuture<void> > futures;

    //Prepare the lambda that does the heavy lifting
    auto lambda = [&] (void) {
        // [...] Heavy lifting goes here
    };

    // Run up some processing
    for(/* any number of heavy liftings we need */){
        // Keep the returned future
        auto future =  QtConcurrent::run(lambda, /* parameters would go here*/ );
        // Store the future around for later
        futures.append(future);
    };

    //Now all the heavy lifting has started, and we are ready to wait for them all to complete.
    for(auto future:futures){
        // Note that if the future finished BEFORE we call this, it will still work.
        future.waitForFinished();
    }

    // Spit out the number of seconds we were running
    quint64 end=QDateTime::currentMSecsSinceEpoch();
    qDebug()<<"DONE after" <<(((qreal)end-start)/1000.0)<<" sec";

    //NOTICE: I did not need an event loop so no app.exec() call here
}

2018年更新

自从我写下这篇回答后,我变得更加智慧,决定分享另一种更为优雅的方法,可以在某些情况下节省您的打字时间和模板代码。这被称为map-reduce,其中美妙的部分是您不需要全部使用它,只需map部分即可。

请注意:这是官方文档中此示例的快速适应。如果您也想保留一些输出数据,请参阅此示例。

// [...] All necessary includes would go here

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);


    // Create a list containing data to be processed
    QList<MyClass> tasks;

    // At this point fill the list of tasks with whatever you need

    // This is the actual code that will run per task
    std::function<void(const MyClass&)> myOperation = [](const MyClass &task)
    {
        qDebug() << "Doing myOperation() in thread" << QThread::currentThread();
        // Do heavy lifting on task object here
    };

    // Start the processing. QConcurrent will automagically start up threads, distribute the tasks and run them taking care of all the tedious threads management for you.
    // It can also take care of collecting the output (not shown in this example).
    // Finally , and most importantly the answer to the question; using the blockingMap will actually block execution until all the work is done.
    QtConcurrent::blockingMap(tasks, myOperation);

    return 0;
}

0
connect(qApp, &QCoreApplication::aboutToQuit, qApp, []() { QThreadPool::globalInstance()->waitForDone(); });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接