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

UI Resposiveness + Multithreaded TCP server-client (UI lags, slow, less responsiveness when 2 client connected)



  • in my QT applications which is designed as a User interface ( UI ) which is updated/refreshed by a PLC controller. The PLC is programmed as a tcp-client which updates the UI every 0.02s after connecting to it.

    The UI is design as a TCPserver, and for each connected PLC@client a new thread is created to process/parse the received data from the PLC and then signal&slots mechanism is used to updated the UI with new received statuses.

    basically the UI resembles LED indicators, any status change in the PLC can be monitored in the UI. Only a maximum of 2 client will connect to it.

    The UI has 2 indicators panel to be updated, 1 panel for PLC-1 and another panel for PLC-2, but the PLC protocol contains data for both the panels, so that when 1 PLC is down, the other PLC can still send data to update both the UI panels. This is just for redundancy purpose.

    the UI is very responsive and runs well when only 1 client (PLC) is connected, both the UI panels have their indicators updated accordingly as to the PLC's, and respond well to the PLC status change, but if the 2nd PLC is also connected, the UI becomes sluggish and less responsiveness. if i disconnect any one of the PLC, then the UI is good response. Only if both PLC connected then it is sluggish & slow, the LED indicators painting becomes slow, if i move to another page by button click also becomes slow... everything is slow when both PLC connected.

    as told before ,for each PLC (client) connected a separate thread will be created, each thread will process the received data and then signals&slots is used to call the function to update the UI panels according to receive data from each thread.

    the reason for my posting is to get some points,tips or hints which i can use to debug the problem, what usually will be problem in this type of architecture ??

    what makes the UI to become less responsive & sluggish when 2 PLC (client) is connected??


  • Qt Champions 2019

    @VikramSamy How often is your UI updated?



  • @jsulm said in UI Resposiveness + Multithreaded TCP server-client (UI lags, slow, less responsiveness when 2 client connected):

    @VikramSamy How often is your UI updated?

    The PLC@client after connect to the tcpserver@UI, will send new datapacket every 0.02s, and if both PLC is connected, both will send the datapacket every 0.02s, the UI is updated every time it receive new data packet from the client.


  • Qt Champions 2019

    @VikramSamy You could reduce the load on UI side by not updating each 0.02sec as this is higher than what a typicsl display can show.


  • Moderators

    @VikramSamy

    taking what @jsulm said to heart, I would suggest the following.

    store all your (after processing) data in a struct and check if any data was actually updated with new values and only then try to emit signals to the ui-thread.

    For emitting the signal to the UI. I would suggest a QTimer and a QTime object. You save the time you last updated the UI, if the time is < than 16 ms (roughly 60hz rate) shedule an update for the next Frame via QTimer if more time passed, send the signal directly.

    You can pass structs in a signal (across threads), if you register it with the Meta-object System



  • for each connected PLC@client a new thread is created

    Only a maximum of 2 client will connect to it.

    Why would you multithread with only 2 clients? you are probably losing efficiency there. See this example



  • @jsulm said in UI Resposiveness + Multithreaded TCP server-client (UI lags, slow, less responsiveness when 2 client connected):

    @VikramSamy You could reduce the load on UI side by not updating each 0.02sec as this is higher than what a typicsl display can show.

    ok i just changed the PLC@client update rate to 0.2s rather than 0.02s as before...quick testing shows that the responsiveness way much better and nice, but previously when i used 0.02s it also good and nice but eventually becomed sluggish...anyway il continue to test and tune the client@PLC update rate and check the resposiveness and will update here..


  • Qt Champions 2019

    @VikramSamy said in UI Resposiveness + Multithreaded TCP server-client (UI lags, slow, less responsiveness when 2 client connected):

    eventually becomed sluggish

    sounds like there is some issue in your code. Maybe memory leaks?



  • @VRonin said in UI Resposiveness + Multithreaded TCP server-client (UI lags, slow, less responsiveness when 2 client connected):

    for each connected PLC@client a new thread is created

    Only a maximum of 2 client will connect to it.

    Why would you multithread with only 2 clients? you are probably losing efficiency there. See this example

    basically the code framework/architecture is already written previously, and im just modifying by adding other stuff to accommodate new requirements, as per that i dont want change the underlying concept used, anyway il look into example and study it.. if my UI & tcpserver implementations really bad concept, then definitely il need to revised it but as for my UI is just simple monitoring page with few button and a firebird database implementations (anyway database is not implemented yet), as for now if its works fine with current architecture then should be ok for me. So the main reason im using this architecture is because alot work have already been done previously and im adding new functionality as per new requirements only... maybe in future we might have more clients connected too....



  • @jsulm said in UI Resposiveness + Multithreaded TCP server-client (UI lags, slow, less responsiveness when 2 client connected):

    @VikramSamy said in UI Resposiveness + Multithreaded TCP server-client (UI lags, slow, less responsiveness when 2 client connected):

    eventually becomed sluggish

    sounds like there is some issue in your code. Maybe memory leaks?

    i need study & check about this memory leak too, stime at begining itself it start to sluggish, and stime after a while....

    but as for now changing the client update rate to 0.2s seems working well...will start test more and update..



  • @J.Hilk said in UI Resposiveness + Multithreaded TCP server-client (UI lags, slow, less responsiveness when 2 client connected):

    @VikramSamy

    taking what @jsulm said to heart, I would suggest the following.

    store all your (after processing) data in a struct and check if any data was actually updated with new values and only then try to emit signals to the ui-thread.

    For emitting the signal to the UI. I would suggest a QTimer and a QTime object. You save the time you last updated the UI, if the time is < than 16 ms (roughly 60hz rate) shedule an update for the next Frame via QTimer if more time passed, send the signal directly.

    You can pass structs in a signal (across threads), if you register it with the Meta-object System

    currently the architecture works similar by passing the processing data in a struct through a signal(across threads) but the signal is immediately emitted once the processing done, there no schedule to update as your suggestion. anyway currently the client is updating every 0.01s (100ms) and as per that the UI have sufficient time refresh itself without getting lag/slow. so far it is working fine.

    Anyway as the data received is to update UI which is 'bar-graph like indicators" which looks like a real time HI-FI graphic equalizer which rises up or down according to signal strength, as per that i just want to continue updating it although there is no status change received, as u suggest i try to update only when status change, but it cause the bar graph patterns getting stalled and not so nice,not going up & down nicely, so as per that i just continue updating no matter got changes or not ...anyway i got another idea as below:-

    as i told before there is 2 PLC updating the server with the same set of data's, one is for redundancy purpose..as both will run in their own separate thread when both is connected and the respective threads emits a signal after completing the data parsing,then the UI update slot is called to refresh the UI to latest status.

    The idea now is to use only 1 set of data from only 1 thread and not use the data returned from the other thread, because updating the UI constantly with same set of data's also another waste processor time and makes the UI lagging and slow.

    So how to block a thread, and only let 1 thread to continuously processing while blocking the other thread,to achieve something as below :- e.g

    thread A and thread B is created after both PLC1 and PLC2 is connected, but only the data returned from thread A is used to update the UI and thread B is blocked from running, thread B only can run if thread A is deleted when the PLC1@client is disconnected and VICE VERSA.

    in other words when both client connected, only thread A data will be used and Thread B must be ignored, if PLC2@client is disconnected then use thread A data from the connected PLC1@client, and when PLC1@client is disconnected then use thread B data....something like this..

    as im new to multi threading or thread based program and also QT, i just try to implement flag in the struct passed by the thread, which states if both client is connected and etc , and checking it before update the UI but it doesnt work...my questions is do we need to use something like mutex or any kind of locking mechanism or this can be achieve by simple flag based communication like in normal embedded c program without threads,


  • Lifetime Qt Champion

    Hi,

    How do you determine that your PLC are connected ?



  • @SGaist said in UI Resposiveness + Multithreaded TCP server-client (UI lags, slow, less responsiveness when 2 client connected):

    Hi,

    How do you determine that your PLC are connected ?

    in the code , there 3 main class/part or i can say 3 object for the communication between the UI and the PLC.

    1. DATA_PROCESS
      which contains the functions to parse the data and a global
      struct to hold received status, within the global struct there is
      a ID variable to identify which PLC send the data.there is also
      private variable called PLC1connect & PLC2connect to set or
      reset PLC connections.

    2. TCP_SERVER- to handle TCP connections....

    3. Connections THREADS
      To receive and parse the data by calling the DATA_PROCESS.

    Once a PLC is connected and a thread is created, the thread will call Data Process Object to parse the data, and after parsing, the ID of the PLC is loaded into the 'status struct', and PLC connection TRUE is set according to the ID received ,so we know which PLC is connected.

    In the DATA_PROCESS code also, a QTimer is set to emit signal every 100ms and connected to a slot called "check_connections", in the check connections function just check if PLC1 connection is TRUE and if yes set to FALSE, and then next check PLC2 connections and if TRUE set it to FALSE and just repeat every time Qtimer emits.

    so basically each time a thread is receiving the data from the PLC client, it will set the Connections to TRUE according to the PLC ID received, and at every 100ms, check_connections function will set it to FALSE, and in the check_connections functions, it is also checked that if it is maintain FALSE for more than the predetermined time, e.g when a PLC is disconnected, then PLC loss status is emitted to the UI thread and PLC communication indicator is off'ed.

    this is how it is determined if the PLC are connected. The thread once received a complete packet with the PLC ID, then the PLC1connect or PLC2connect is set to TRUE and disconnection is check by the check_connections functions as above

    So what im thinking here is, now got 2 threads calling the DATA_PROCESS object and updating the received data to the 'status struct' and then emitted to the UI by calling the UI update functions/slot. This calling of DATA_PROCESS is done in the "Connection_Thread::Ready_Read()".

    So i guess i need lock one of thread,(or atleast stop it from emitting its update signal) when both PLC are connected, and only allowed 1 thread to do the processing and updating, and if the particular PLC is disconnected & its thread destroyed, then unlock the other thread to continue the processing,.. basically this to achieve redundancy when 1 PLC fails we still have the data of the other PLC to update the UI, anyway i need to do it in software because i have some hardware limitation/PLC programming limitation to support the PLC redundancy.


  • Lifetime Qt Champion

    Rather than having both your PLCs competing to write in some global structure. You should rather have them independently fill each their own structure and have some sort off watchdog switching from one or the other if needed.

    Depending on the how often the PLC are supposed to send data, you should maybe consider restarting the network check when you receive data rather than having that again competing with incoming data.