3

I can't find any clear solution to this. I have a thread started with QtConcurrent::run(). When I close the application before the thread is finished, the application crashes. I want the application to close after all backgroud threads (QtConcurrent::run()) have finished. How do I solve this?

demonplus
  • 5,613
  • 12
  • 49
  • 68
Kevin yudo
  • 233
  • 4
  • 15
  • `QFuture future = QtConcurrent::run(yourFunction);` then you need to wait it to be finished : `future.waitForFinished();` – IAmInPLS May 18 '16 at 11:54
  • Thaks Alexis.İf I use future.waitForFinished() , GUi is locked . This must be background thread.When I close to Apps , QtConcurrent::run() must be finished – Kevin yudo May 18 '16 at 13:10
  • Then, look at this question : http://stackoverflow.com/q/12527141/5653461 and its answer of course – IAmInPLS May 18 '16 at 13:17
  • Use `QFutureWatcher::finished` signal. – thuga May 18 '16 at 13:49
  • how many threads are you starting? are you using `QtConcurrent::run()` from many classes? maybe you can use `future.waitForFinished()` in the destructors of the classes that are starting your threads. – Mike May 18 '16 at 16:58

2 Answers2

4

I came here looking for the same thing as you and ended up solving it in my own way. This is my approach:

// [...] 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
}

UPDATE 2018

I have since I wrote this answer gotten wiser, and decided to share another way to do that in some cases will be more elegant and save you some typing/boilerplate. It is called map-reduce and the nice bit is you don't need all of it, just the map part will work fine.

NOTE: It is a quick adaption of this example in the official documentation. See this example if you want to retain some output data as well.

// [...] 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;
}
Mr. Developerdude
  • 9,118
  • 10
  • 57
  • 95
0
connect(qApp, &QCoreApplication::aboutToQuit, qApp, []() { QThreadPool::globalInstance()->waitForDone(); });
Moez Gadri
  • 11
  • 1