UI Application as thread - CPU Load almost 100%



  • Hi,
    As per my requirement, After starting up the UI, I need to do some more processing. So, I cannot create QApplication object in my main(). Rather, I call a function in a thread and from that thread, I create QApplication object and running UI as thread.
    Problem with this approach is that,
    I notice that, CPU consumption by my application is always 100%.

    Any thoughts on this?

    Thanks,
    Kumara



  • @kumararajas Hi! I don't think you can run the GUI in a different thread than the main thread as the documentation says:

    As mentioned, each program has one thread when it is started. This thread is called the "main thread" (also known as the "GUI thread" in Qt applications). The Qt GUI must run in this thread. All widgets and several related classes, for example QPixmap, don't work in secondary threads. A secondary thread is commonly referred to as a "worker thread" because it is used to offload processing work from the main thread.


  • Qt Champions 2016

    @Wieland said:

    I don't think you can run the GUI in a different thread than the main thread

    Actually, it is possible in principle, but only provided the GUI thread is the only thread accessing the GUI, which mostly defeats the whole purpose of starting a new thread for it. :)

    So, I cannot create QApplication object in my main().

    I don't follow. Why is that? You can start a worker thread and do whatever is you do there, how is this directly impeding you from creating the QApplication object in main.

    Rather, I call a function in a thread and from that thread, I create QApplication object and running UI as thread.

    "How" is key here? Please provide some source.

    Kind regards.



  • The application is that,
    UI is configurable in my system. If the LCD is not connected, I don't need UI Application to be running. So, my main application, checks for the configuration and based on that, I start the UI. That's one thing. And, I do have other processing to be done, apart from displaying the user interface. So, I start the UI, and continue to do my job in the background.

    Do you see any misunderstanding with my thoughts?

    I dont see the reason on "why" GUI cant be in a worker thread and do whatever in my own space, which is as close to UI being run from Main Thread.

    And when I have implemented, yes, I am able to run the UI from the worker thread. I havent tested all Qt features though.

    But the problem I have is, CPU being loaded to 100%. But, I had a way to overcome this by calling pthread_exit soon after creating the thread. It doesnt makes sense to me. But, this pulls the CPU load to minimal.

    Here is how my code looks like -

    int main(void)
    {
    startApp();
    // UI is running in a thread. Let's continue to do other activities.
    }
    
    void startApp()
    {
        pthread_t uiThread;
    
        int argc = 0;
        char *argv[1];
        InputArgs args = {argc, argv};
        int rc = pthread_create(&uiThread, NULL, startUIAsThread, (void*)&args);
        pthread_exit(NULL);
    }
    
    void *startUIAsThread(void *threadArgs)
    {
        InputArgs *args = (struct InputArgs*) threadArgs;
        createUserInterface(*args);
    }
    
    void createUserInterface(InputArgs args)
    {
        QApplication *uiApp = new QApplication(args.argc ,
                                               args.argv ,
                                               QApplication::GuiServer);
        uiApp->exec();
    }
    

    Do you see any problem with my code?

    Thanks,
    Kumara



  • Best to place high loads seperate from ui thread but when load gets very high then even windows explorer will hang.


  • Qt Champions 2016

    @kumararajas said:

    Do you see any misunderstanding with my thoughts?

    Well, I wouldn't start the GUI in another thread. I'd do something like this:

    int main(int argc, char ** argv)
    {
        QApplication app(argc, argv);
        if (lcdIsConnected())
            return QApplication::exec();
    
       doThingsThatDontRequireGUI();
       return 0;
    }
    

    Do you see any problem with my code?

    A few, yes.

    • Firstly, you're using a very convoluted way to start a thread. If you shall ask, Qt shall provide - simply use QThread.
    • Secondly, pthread_exit(NULL); kills your main thread (where main() is run), which ain't good at all.
    • Thirdly, you create an application object and you never delete it.
    • And lastly, What's QApplication::GuiServer and why are you passing it to the QApplication object?

    So. Try something along the lines of this (main.cpp):

    class AppThread : public QThread
    {
    public:
        AppThread(int &, char ** &);
    
    protected:
        void run() override;
    
    private:
        int & argc;
        char ** & argv;
    };
    
    AppThread::AppThread(int & n, char ** & nstr)
        : argc(n), argv(nstr)
    {
    }
    
    void AppThread::run()
    {
        QApplication app(argc, argv);
        app.exec();
    }
    
    int main(int argc, char ** argv)
    {
        AppThread thread(argc, argv);
        thread.start();
        
        // ... Do other stuff ...
    
        thread.wait();
        return 0;
    }
    


  • Hi,
    Here are my thoughts and answers..

    First of all -

    int main(int argc, char ** argv)
    {
        QApplication app(argc, argv);
        if (lcdIsConnected())
            return QApplication::exec();
    
       doThingsThatDontRequireGUI();
       return 0;
    }
    

    In the above code. If LCD is connected, then exec() gets executed, which is a blocking call. And doThingsThatDontRequireGUI(); never gets called. This is not what I want. Even if LCD is present or not, I should be able to execute doThingsThatDontRequireGUI();

    Answering to the points.
    > Firstly, you're using a very convoluted way to start a thread. If you shall ask, Qt shall provide - simply use QThread.
    That is a good idea. I can use QThread. However I just went with posix function. I can use that for sure.
    > Secondly, pthread_exit(NULL); kills your main thread (where main() is run), which ain't good at all.
    Agree with you. This is a bad idea. I had this statement to reduce the CPU load. But I know this is not good at all.
    > Thirdly, you create an application object and you never delete it.
    I haven't deleted because the object's life time is till the end of application. Agree, I need to free up the memory during destruction process.
    > And lastly, What's QApplication::GuiServer and why are you passing it to the QApplication object?
    Thjs is something I have tried out.When we run Qt application on embedded platform, we should be passing -qws. I just don't want to pass this option for my application needs. This helps me to start the QWS server by itself rather than passing the argument -qws.

    I am going to give a try with the example you have provided. All I need is CPU load to be as less as possible. I will test and keep you posted with the results.

    Thank you,
    Kumara


  • Moderators

    Why not execute doThingsThatDontRequireGUI() in another thread?


  • Qt Champions 2016

    @kumararajas

    In the above code. If LCD is connected, then exec() gets executed, which is a blocking call. And doThingsThatDontRequireGUI(); never gets called. This is not what I want. Even if LCD is present or not, I should be able to execute doThingsThatDontRequireGUI();

    You can do that in the main thread, but I see your point. If doThingsThatDontRequireGUI() is long it'd hang up the main thread. But then, as @jsulm said, why not thread that particular function?

    For example:

    class MyInitThread : public QThread
    {
    protected:
        void run() override;
    };
    
    void MyInitThread::run()
    {
        doThingsThatDontRequireGUI(); //< Do whatever it is you require for initialization here
    }
    
    int main(int argc, char ** argv)
    {
        MyInitThread initThread;
        initThread.start();
    
        int retValue = 0;
           
        if (lcdIsConnected())  {
            QApplication app(argc, argv);
            retValue = QApplication::exec();
        }
    
        initThread.wait();
        return retValue;
    }
    

    I haven't deleted because the object's life time is till the end of application. Agree, I need to free up the memory during destruction process.

    Although the OS probably cleans up the object, I firmly believe you should take care to free your objects.

    This helps me to start the QWS server by itself rather than passing the argument -qws.

    Fair enough.



  • Here I am with the results.

    When I create a worker thread and create QApplication in it, I get this message -

    WARNING: QApplication was not created in the main() thread.
    

    And UI doesn't comes up.

    I wonder why Qt looks for Main Thread during instantiation of QApplication.

    I like the approach of creating a thread and performing the operations that does not depends on GUI, the business logics.

    Here is the reason that, I dont want to create QApplication and get blocked by calling exec in the main().
    I have main(), that creates various child processes for various operations. One of the process is meant for UI. And the UI child process is suppose to create UI and also look for other operations.

    I can do that too, like creating a thread for such other operations and get the main thread of child process blocked.

    My perception was that, main thread and worker threads are same. Just that main thread is not user created one.


  • Qt Champions 2016

    @kumararajas said:

    When I create a worker thread and create QApplication in it, I get this message

    There's a reason for that. Qt has internally quite a lot of statics and it keeps track of them. They are unprotected for the most part and can't be just accessed from any thread. You get that message, because I misled you, sorry for that. QThread's constructor will ultimately set the main thread internally, so that's why you get the warning. Here's a much better example, that might run okay (or it might not):

    #include "mainwindow.h"
    
    #include <QApplication>
    #include <thread>
    
    void fakeMain(int argc, char ** argv)
    {
    	QApplication a(argc, argv);
    	MainWindow w;
    	w.show();
    
    	QApplication::exec();
    }
    
    int main(int argc, char ** argv)
    {
    	std::thread fakeMainThread(fakeMain, argc, argv);
    
    	fakeMainThread.join(); //< This is really important, do not remove it.
    	return 0;
    }
    

    EDIT: I tested the example on my Debian it appears to run okay.

    Still, I continue to believe you should move your code out of main, put it in a worker thread and run Qt in the main one.

    My perception was that, main thread and worker threads are same. Just that main thread is not user created one.

    They are in principle, yes.



  • @kshegunov

    That's a good thought!

    I live in a basic environment that doesn't support C++ 11, So, std::thread won't work for me.

    However, I can use posix API pthread_create. This goes back to the loop. If I replace std::thread with pthread_create in the example you have provided, I arrive at my old example (in the top of this conversation)

    One eye opener, which I have got in your example is pthread_join

    In my example, I was using pthread_exit which is absolutely not accepted to terminate the calling thread, in my case it was a main thread. It was a blunder.

    Instead of that, now I have updated my code to call pthread_join. This works charm. I am able to bring down the CPU to a least number. This was an outcome of my basic testing. I will continue to perform various tests further.

    However, that's a good point on moving my business code from main to the worker thread. I shall think about it.

    Thanks for all those healthy discussions. I am glad that, I got a chance to discuss a lot with the experts like you!



  • So as suggested, I have updated my code that runs UI in the main thread and gets blocked. And, I have worker thread that performs some of business logics.

    It did not matter to me when I ran the UI in a worker thread. However, I opted to change my way, because of experts suggestions.

    Thank you all!

    --Kumara


Log in to reply
 

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