Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Why QtConcurrent::run freezing my program?



  • I read QString from the database which has a lot of data
    I want to split QString line by line and then use it,
    When I use the for to split it, my app freezes and doesn't work,
    I found that the run function QtConcurrent :: run a function in a separate thread
    I did as below, but my application still freeze when calling function readfile

    void MainWindow::getData(){
     QString getRecord=dbFile->getRecord(IdGet);
    
        QFuture<void> t1 = QtConcurrent::run(demoSimple,&ZoomScrollTrack2::readfile, getRecord);
    
        t1.waitForFinished();
    }
    
    void Track::readfile(QString Record){
    
    
        for(int u=0;u<Record.size();u++){
            QStringList line=Record.split("#");
             qDebug()<<"record list"<<line;
    
    }
    }
    

    I try to use this way but I have error (no matching function for call to run)

    QFuture<QList<QString>> future = QtConcurrent::run(IdGet, &QString::split, '#');
       QList<QString> result = future.result();
        qDebug()<<"list"<<result;
    

    Is QtConcurrent::run function is a good way for my action or I need to use QThread with subclass?


  • Lifetime Qt Champion

    Since you're directly waiting for the result your gui freezes. You should connect to the QFuture signals and/or use QFutureWatcher. See https://doc.qt.io/qt-5/qtconcurrent-index.html


  • Moderators

    @isan additional to what @Christian-Ehrlicher said, you may want to consider using splitRef('#') it returns a QVector<QStringRef> instead of a QList<QString> it is significantly faster, but it depends on the lifetime of the original QString!



  • @isan You need to use QFutureWatcher in combination with QEventLoop to not lock you main thread.
    Something like this:

    // start process in another thread
    QFuture<void> future = QtConcurrent::run(demoSimple,&ZoomScrollTrack2::readfile, getRecord));
    
    QFutureWatcher<void> watcher;
    QEventLoop loop;
    // QueuedConnection is necessary in case the signal finished is emitted before the loop starts
    // (if the task is already finished when setFuture is called)
    connect(&watcher, SIGNAL(finished()), &loop, SLOT(quit()),  Qt::QueuedConnection); 
    watcher.setFuture(future);
    qDebug()<<"wait for result";
    
    // passive wait until QFuture is finished
    loop.exec();
    qDebug()<<"done";
    


  • Thanks for your help
    It works, but it takes a few minutes, is there a better way to make it faster?


  • Moderators

    @isan compiling and running it in release mode will make it a good bit faster.

    besides that, truncating your QString beforehand and running multiple QtConcurrent each one with part of the original string?


  • Lifetime Qt Champion

    @kromignon said in Why QtConcurrent::run freezing my program?:

    You need to use QFutureWatcher in combination with QEventLoop to not lock you main thread.

    This contradicts the whole idea to move the heavy work into an own thread...


  • Lifetime Qt Champion

    @isan said in Why QtConcurrent::run freezing my program?:

    for(int u=0;u<Record.size();u++){
    QStringList line=Record.split("#");
    qDebug()<<"record list"<<line;

    I hope this is not your real function since it basically does Record.size() times the same.



  • @christian-ehrlicher
    yes you said right, it should work without for()


Log in to reply