QtConcurrent 在 App 即将退出时等待完成
QtConcurrent wait for finished when App is about to quit
我找不到任何明确的解决方案。我有一个以 QtConcurrent::run()
开头的话题。当我在线程完成之前关闭应用程序时,应用程序崩溃。我希望应用程序在所有后台线程 (QtConcurrent::run()
) 完成后关闭。我该如何解决?
我来这里是为了寻找和你一样的东西,最后用我自己的方式解决了它。这是我的方法:
// [...] 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 年更新
自从我写了这个答案后,我变得更聪明了,并决定分享另一种方法,在某些情况下会更优雅并为您节省一些 typing/boilerplate。它被称为 map-reduce,好处是你不需要全部,只需要 map 部分就可以了。
注意:这是对官方文档中 this example 的快速改编。如果您还想保留一些输出数据,请参阅此示例。
// [...] 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;
}
我找不到任何明确的解决方案。我有一个以 QtConcurrent::run()
开头的话题。当我在线程完成之前关闭应用程序时,应用程序崩溃。我希望应用程序在所有后台线程 (QtConcurrent::run()
) 完成后关闭。我该如何解决?
我来这里是为了寻找和你一样的东西,最后用我自己的方式解决了它。这是我的方法:
// [...] 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 年更新
自从我写了这个答案后,我变得更聪明了,并决定分享另一种方法,在某些情况下会更优雅并为您节省一些 typing/boilerplate。它被称为 map-reduce,好处是你不需要全部,只需要 map 部分就可以了。
注意:这是对官方文档中 this example 的快速改编。如果您还想保留一些输出数据,请参阅此示例。
// [...] 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;
}