Unsolved Issue in making GUI responsive
-
Hello All,
I am working on application where i have to move my device to cetain location on start button click event.
My problem is when the device is moving my application freezes for time being the device have not moved. So basically i am reading data sequentially waiting for the response data before executuing the next step.
So the solution for me was to implement the operation in a thread. I have implement thread using QtConcurrent and than i get the following run time error:Error:QObject: Cannot create children for a parent that is in a different thread.
(Parent is QSerialPort(0x20740c92860), parent's thread is QThread(0x20740c47600), current thread is QThread(0x207410864c0)
So from my understanding QSerialPort is initialized in serialport.cpp file so it cannot be executed from the thread which is invoked in serialport.cpp.
In my program is i have defined all the serialrelated functions in serialpost.cpp file.So i just want to know what elese can be done. And that i what should be the currect approach that i should follw to implement the same
-
It sounds like your application is overwhelmed by the amount of data generated while moving the device. Reading the data in a separate thread may be a viable solution. However, QtConcurrent does not sound like the right tool for this job.
QtConcurrent helps you divide work onto multiple cores to speed up processing. What you really need is to keep the UI responsive while data is being processed in the background. This is a different use case for threads, and can be done using QThread.
Without any code samples or more information on what exactly you are trying to achieve, I find it difficult to give any more specific advice.
-
@Asperamanca : I will update with code. But even if we use code QThread than also i think:
Error:QObject: Cannot create children for a parent that is in a different thread. is expected to arise. -
@Kira said in Issue in making GUI responsive:
is expected to arise
If you use Qt threads in a wrong way, then yes.
Create your QSerialPort instance in the thread where you want to use it and do not access it anywhere else. -
@jsulm : Thanks for the reply from the error i was able to understand something like that was happening.
So i will have to do the following ??- Close the instance of serialPort in mainthread.
- Initialize serialport in thread
- Do the required operation
4.Close the serialport in thread and again open it in the mainthread.
-
@Kira said in Issue in making GUI responsive:
@jsulm : Thanks for the reply from the error i was able to understand something like that was happening.
So i will have to do the following ??- Close the instance of serialPort in mainthread.
- Initialize serialport in thread
- Do the required operation
4.Close the serialport in thread and again open it in the mainthread.
No. Create a thread dedicated to read the serial port. Communicate results with your main thread using signals and slots. Be aware that all communication that way will be asynchronous.
-
@Asperamanca : Actually i have to keep my serialrequest synchronous.
-
@Kira what part of it, and why?
-
@J.Hilk : Ok i understand what @Asperamanca is trying to explain. Actually as per the requirement i have to give signal to the controller to move and capture the images at that location and repeat the operation n number of times. I am performing this operation in main thread which is causing main thread to freeze until the controller moves to the location.
Using the below codes:serialPort->write(serialCommand.toUtf8()); serialPort->waitForReadyRead(); //qDebug()<<"Bytes arrived"<<serialPort->bytesAvailable(); readData = serialPort->readAll();
@J-Hilk : are you suggesting to create a thread which serves the serialrequest to avoid freezing of the mainthread and get the acknowledgement via signal slot mechanism from the thread.
As per my current experience with the program it is not feasible to create separate thread as it is called multiple times as it causes a lot of overhead. -
@Kira said in Issue in making GUI responsive:
serialPort->waitForReadyRead();
You're calling this in main thread?!
Why don't you use the asynchronous nature of QSerialPort instead? -
@Kira
The idea is to create 1 additional thread, probably during application start up.In that your Serialport lives, sending and receiving data and sitting idle when nothing is to be done.
Creating a new thread and serialport instance each time you want send/receive data has indeed way too much overhead.
I assume you get a message back, when your controller finished moving? You can react to that via a Signal that you emit, to your main thread
-
@J.Hilk said in Issue in making GUI responsive:
I assume you get a message back, when your controller finished moving? You can react to that via a Signal that you emit, to your main thread
Ok so this is the approach i should follow?
@jsulm said in Issue in making GUI responsive:
Why don't you use the asynchronous nature of QSerialPort instead?
@jsulm : I have tried that initially but it's not that effective? Basically there are so many request and response that sometimes i don't get response and s.ometimes previous and current responses together which is not feasible
-
@Kira said in Issue in making GUI responsive:
I have tried that initially but it's not that effective? Basically there are so many request and response that sometimes i don't get response and s.ometimes previous and current responses together which is not feasible
Sounds like something is wrong then - I doubt moving QSerialPort to another thread will change this behaviour.
-
@Kira said in Issue in making GUI responsive:
Ok so this is the approach i should follow?
Imho, yes
I have tried that initially but it's not that effective? Basically there are so many request and response that sometimes i don't get response and s.ometimes previous and current responses together which is not feasible
Seems to me like you're missing a proper queue implementation on your SerialPort communication.
-
@J.Hilk said in Issue in making GUI responsive:
Seems to me like you're missing a proper queue implementation on your SerialPort communication.
@J-Hilk : I have tried multiple example also with the sample examples that comes with the qt creator. I was having problem with the microcontroller version which i was using.
As per what i have understood about signal slot mechanism is that if the slot is not executed at given instance of time it get queued. So their arise a possiblity of the slots getting queue and be the reason of my delay in response creating a bottleneck between the sender and the receiver.
-
@Kira A signal is only queued when communicating between different threads (or setting queued connection type explicitly). In same thread emitting a signal means that all connected slots will be called immediately one after another (in same order as connect() calls), so no queueing.
-
@jsulm : @J-Hilk : Guys thanks to you did some sample program regarding implementation of QSerialPort and found an interesting example listed under qt creator.
https://doc.qt.io/qt-5/qtserialport-blockingmaster-example.html
Here they have clearly mentioned the example of using serialPort in gui mode.
Just i have one doubt:
=>Here every time port is being set, i don't have any such condition in my example so can just set port once in the thread ?
=>Also does QWaitCondition have any extra overhead ?
=>Can i implement the similar logic for my camera thread where the thread runs continuously without any sleep? -
@Kira That example shows how to use SYNCHRONOUS API in GUI thread. But why do you want to use synchronous API instead of the asynchronous? If there is no valid reason to use synchronous API use the asynchronous - this is WAY easier compared to dealing with threads.
-
@Kira and just to add to @jsulm:
I doubt the serial port handling is your problem. Serial ports are slow and handling them with signals and slots is most often no problem.
I think your problem is handling the data you received through serial port. If that takes a bit longer, you'll block your GUI.
Regards
-
@jsulm said in Issue in making GUI responsive:
That example shows how to use SYNCHRONOUS API in GUI thread.
Will this approach cause my GUI to hang if i don't get a timely response??
Can you please suggest how can i implement the following requirement using asynchronous approch?
->Send serial data
->Read the data
->If data read successfully than allow another serial request.