QThread freezing the UI!



  • Good day to everyone!
    Here I am again to ask for help!

    In my project I'm using a thread to perform a export process. The export process consists in convert a database model in a SQL script and export snippets of the script to the database server.

    Well, for small models ( ~200 objects) everything is running fine. But when I try to export a huge model the process runs flawlessly until it reaches 70-80% and then the thread gradually start to drain one core of my CPU freezing the entire UI until the ends of its job. I've tried everything to solve but no success...

    Basically I've have two classes involved: a worker and the form to configure the export. In my code I have something like this:

    // Export form
    ExportForm::ExportForm(...)
    {
      export_thread=new QThread(this);
      export_worker.moveToThread(&export_thread);
    }
    ...
    void ExportForm::exportModel()
    {
      ...
      export_thread->start();
      ...
    }
    
    // Export worker
    ...
    void ExportWorker::exportBuffer(...)
    {
      ...
      while(!buffer.atEnd() && !export_cancelled)
     {
       //performing lots of operations here.
      QThread::msleep(50);
     }
    }
    

    The export_cancelled flag is activated from a slot connected in the ExportForm to give user the ability to abort the process anytime.

    I've read somewhere that putting a thread to work with a loop can cause the mentioned behavior (CPU drain and UI freeze). But I need the export to work that way. Someone have any suggestion? A better approach?
    I'm quite confusing and frustrated with all this and any help is welcome!

    P.S.: Sorry about my English!



  • Are you sure that your function is getting executed in the new thread ? I'm thinking that your UI thread only must be doing export task. This must be the reason for hang of UI. Did you put connect statement for thread start and your slots ?



  • Yes. I'm connecting QThread::started to the ExportWorker::exportBuffer. I'll double check if the thread executing the process is the same as the UI. Thanks!



  • Confirming that the threads are different... Below a simple output.
    Each thread prints its own address (converted to ulong) and where they are (Worker or Form)...

    Form - Thread: 9047552
    Worker - Thread: 54738656
    Worker - Thread: 54738656
    Worker - Thread: 54738656
    Form - Thread: 9047552
    Worker - Thread: 54738656
    Worker - Thread: 54738656
    Worker - Thread: 54738656
    Worker - Thread: 54738656
    Form - Thread: 9047552
    Form - Thread: 9047552
    


  • This post is deleted!


  • How about trying to fork() it?



  • Another thing that comes to mind is concurrent programming, read about that this weekend and guess it might be an idea to try as good as any other.



  • @andsun Fork a thread? How to do that?



  • check out this fork smaple


  • Moderators

    @andsun said:

    check out this fork smaple

    There is no need to fork() if you use QThread.

    @rkhaotix said:

    Confirming that the threads are different... Below a simple output.
    Each thread prints its own address (converted to ulong) and where they are (Worker or Form)...

    Did you print these values from inside ExportWorker::exportBuffer()?

    I've read somewhere that putting a thread to work with a loop can cause the mentioned behavior (CPU drain and UI freeze). But I need the export to work that way. Someone have any suggestion? A better approach?
    I'm quite confusing and frustrated with all this and any help is welcome!

    You need to provide lots more information:

    1. Do you transfer any data between the 2 threads? If so, how?
    2. How is the buffer filled?
    3. Where does the exported data go?
    4. Which thread creates your QSqlDatabase object?


  • @JKSH Thanks for you reply!

    Answering your questions...

    1. The only data I transfer between threads are messages and process progress through signals from Worker Thread to Form Thread (UI). Basically a QString and int instances.

    2. The buffer is filled in the Worker side. It will call the method in database model instance that will produce a QString. After that I iterate line by line in that string using QTextStream.

    3. The processed SQL for each object is then passed to a instance of a class called Connection (a libpq encapsulation made my me). I don't use the SQL/DB classes provided by Qt.

    My project is open source but I won't post the code here due its size... If you have any interest here goes the links:

    Form class: https://github.com/pgmodeler/pgmodeler/blob/develop/libpgmodeler_ui/src/modelexportform.cpp
    Worker (or Helper) class: https://github.com/pgmodeler/pgmodeler/blob/develop/libpgmodeler_ui/src/modelexporthelper.cpp

    See methods ModelExportForm::exportModel() and ModelExportHelper::exportBufferToDBMS().


  • Moderators

    Hi @rkhaotix,

    I had a quick look at your code. It's too big for me to go through properly, and I didn't spot anything obvious that maxes out your CPU.

    However, I noticed a few things which might be related:

    • Your ModelExportHelper constructor is run in the main thread, so it opens the DB connection in the main thread. Are you sure you can use that connection in the worker thread after this?
    • In line 56 of modelexportform.cpp: the lambda runs in the signalling (GUI) thread, not the worker thread. Note that, while the QThread manages the worker thread, the QThread object itself lives in the GUI thread.
    • Your ModelExportHelper uses some GUI-related classes: QGraphicsView, QPixmap. These classes must only be used in the GUI thread.
    • Your ModelExportHelper includes "modelwidget.h". Why? Widgets must only be used in the GUI thread.

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.