Results 1 to 8 of 8

Thread: Best way to send data from a GUI thread to a processing thread?

  1. #1
    Join Date
    Jan 2010
    Posts
    18
    Thanks
    8
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Best way to send data from a GUI thread to a processing thread?

    As the topic suggests, I'm looking for the best way to send data from the main window GUI thread to a processing thread.

    At the moment, the run() function in the ProcessingThread looks something like this:
    Qt Code:
    1. void ProcessingThread::run()
    2. {
    3. while(1)
    4. {
    5. frame=grabFrame();
    6. if(flag1)
    7. doProcessingOnFrame1(frame,setting1,setting2);
    8. if(flag2)
    9. doProcessingOnFrame2(frame,setting3,setting4);
    10. if(flag3)
    11. doProcessingOnFrame3(frame,setting5,setting6);
    12.  
    13. emit newFrame(frame);
    14. }
    15. }
    To copy to clipboard, switch view to plain text mode 

    MainWindows.cpp has:
    Qt Code:
    1. // Create queued connection between processing thread (emitter) and GUI thread (receiver/listener)
    2. connect(controller->processingThread,SIGNAL(newFrame(QImage)),this,SLOT(updateFrame(QImage)),Qt::QueuedConnection);
    To copy to clipboard, switch view to plain text mode 

    and also:
    Qt Code:
    1. void MainWindow::updateFrame(const QImage &frame)
    2. {
    3. // Update public "flags" and "settings" members in ProcessingThread
    4. updateData();
    5. // Display frame in main window
    6. frameLabel->setPixmap(QPixmap::fromImage(frame));
    7. } // updateFrame()
    To copy to clipboard, switch view to plain text mode 

    Eveything works perfectly

    However, at the moment I am updating/changing the "flags" and "setting" variables contained within the ProcessingThread by making them public and then altering them within updateFrame() in MainWindow.cpp (see above). This is merely my attempt update them "synchronously" after each loop of run() - so that they don't change in the middle of the execution of run() and thus erroneousness turn on more image processing than that actually set by the user.

    However, it is my understanding that run() does not block when emitting the newFrame signal in the case of a queued-connection - thus the data update is not truly synchronous.

    There has to be a better way to do change these variables in response to GUI events in MainWindow.

    Here is a method I was thinking of:

    Create a binary semaphore (initialized to 1) and use it like so in run():

    GLOBAL: sem = new QSemaphore(1);

    Qt Code:
    1. void ProcessingThread::run()
    2. {
    3. while(1)
    4. {
    5.  
    6. frame=grabFrame();
    7.  
    8. sem->acquire();
    9. if(flag1)
    10. doProcessingOnFrame1(frame,setting1,setting2);
    11. if(flag2)
    12. doProcessingOnFrame1(frame,setting3,setting4);
    13. if(flag3)
    14. doProcessingOnFrame1(frame,setting5,setting6);
    15. sem->release();
    16.  
    17. emit newFrame(frame);
    18. }
    19. }
    To copy to clipboard, switch view to plain text mode 

    And then merely use this global semaphore in the updateFrame() slot in MainWindow:
    Qt Code:
    1. void MainWindow::updateFrame(const QImage &frame)
    2. {
    3. // Update public "flags" and "settings" members in ProcessingThread
    4. sem->acquire();
    5. updateData();
    6. sem->release();
    7. // Display frame in main window
    8. frameLabel->setPixmap(QPixmap::fromImage(frame));
    9. } // updateFrame()
    To copy to clipboard, switch view to plain text mode 

    However, this method again relies on making the "flags" and "settings" variables PUBLIC in ProcessingThread...

    Is there a better way?

    I'm open to and would really appreciate any suggestions
    (If I have omitted any crucial information, please let me know.)

    Thanks in advance to anyone who could help me with this!

  2. #2
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,716
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Best way to send data from a GUI thread to a processing thread?

    However, this method again relies on making the "flags" and "settings" variables PUBLIC in ProcessingThread...
    Is there a better way?
    Make them protected/private and give the setters/getters?
    And you should mutex them!
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  3. #3
    Join Date
    Jan 2010
    Posts
    18
    Thanks
    8
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Best way to send data from a GUI thread to a processing thread?

    Thanks for the reply! The only problem with that idea is that set/get functions for each variable could get quite tedious when the number of settings and flags are numerous.

    I was also thinking about creating a signal/slot connection from the GUI thread to the processing thread which passes a structure containing all the flags and settings to the thread on every setting change GUI event.

    Something like this (in MainWindow.cpp):
    Qt Code:
    1. connect(this,SIGNAL(newData(struct data)),this,SLOT(updateData(struct data)),Qt::QueuedConnection);
    To copy to clipboard, switch view to plain text mode 

    Slot in ProcessingThread:
    Qt Code:
    1. void updateData(struct data)
    2. {
    3. sem->acquire();
    4. // save structure contents to ProcessingThread private members:
    5. flag1=data.flag1;
    6. flag2=data.flag2;
    7.  
    8. //etc.
    9. sem->release();
    10. }
    To copy to clipboard, switch view to plain text mode 

    And also use sem in MainWindow followed by emit newData(data) when GUI events change the values contained in the structure "data". For example (slot connected to gui event):
    Qt Code:
    1. void onButtonPush()
    2. {
    3. sem->acquire();
    4. data.flag1=true;
    5. sem->release();
    6. emit newData(data);
    7. }
    To copy to clipboard, switch view to plain text mode 

    Is this also a valid/safe solution?
    I remember reading that slots in a thread are a bad idea?
    Also, can "emit" be used in a SLOT?

    Thanks!

  4. #4
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,716
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Best way to send data from a GUI thread to a processing thread?

    Thanks for the reply! The only problem with that idea is that set/get functions for each variable could get quite tedious when the number of settings and flags are numerous.
    You could group them in groups that make sense in your applications logic (structs?).

    The problem with signal and slots among threads is not that they are not safe, they are, and is probably the best way to transfer data between threads in Qt, however they are queued - so you don't know when that data is arrived and set, which in your case I think is important (per frame, for a specific frame).
    So in your case you have to set() get() them.
    Public members is VERY bad idea, and its very dangerous.
    And don't forget to mutex them!
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  5. #5
    Join Date
    Jan 2010
    Posts
    18
    Thanks
    8
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Best way to send data from a GUI thread to a processing thread?

    Quote Originally Posted by high_flyer View Post
    You could group them in groups that make sense in your applications logic (structs?).

    The problem with signal and slots among threads is not that they are not safe, they are, and is probably the best way to transfer data between threads in Qt, however they are queued - so you don't know when that data is arrived and set, which in your case I think is important (per frame, for a specific frame).
    So in your case you have to set() get() them.
    Public members is VERY bad idea, and its very dangerous.
    And don't forget to mutex them!
    The most important thing is that all the flags and settings get updated at the same time before or after processing is finished. In other words, I don't want the flags/settings being updated straight after for example "if(flag1) ..." (below in run()) as this will momentarily turn on the wrong combination of processing.

    This is what I have chosen to do: (and it seems to be working)

    ProcessingThread.cpp
    Qt Code:
    1. void ProcessingThread::run()
    2. {
    3. while(1)
    4. {
    5. frame=grabFrame();
    6. mutex.lock();
    7. if(flag1)
    8. doProcessingOnFrame1(frame,setting1,setting2);
    9. if(flag2)
    10. doProcessingOnFrame2(frame,setting3,setting4);
    11. if(flag3)
    12. doProcessingOnFrame3(frame,setting5,setting6);
    13. mutex.unlock();
    14. emit newFrame(frame);
    15. }
    16. }
    To copy to clipboard, switch view to plain text mode 

    Slot in ProcessingThread.cpp
    Qt Code:
    1. void ProcessingThread::updateProcessingFlags(struct ProcessingFlags p_flags)
    2. {
    3. QMutexLocker locker(&mutex);
    4. // Update private members of ProcessingThread
    5. this->flag1=p_flags.flag1;
    6. this->flag2=p_flags.flag2;
    7.  
    8. // etc
    9. } // updateProcessingFlags()
    To copy to clipboard, switch view to plain text mode 

    In the main window GUI slots:
    Qt Code:
    1. emit newProcessingFlags(processingFlags);
    To copy to clipboard, switch view to plain text mode 

    And of course again in MainWindow.cpp:
    Qt Code:
    1. qRegisterMetaType<struct ProcessingFlags>("ProcessingFlags");
    2. connect(this,SIGNAL(newProcessingFlags(struct ProcessingFlags)),controller->processingThread,SLOT(updateProcessingFlags(struct ProcessingFlags)),Qt::QueuedConnection);
    To copy to clipboard, switch view to plain text mode 

    (Note: The updating of the settings is also done exactly the same way as above)

    Does this seem like a reasonable solution to anyone? I'd appreciate any comments at all.

    Thanks

  6. #6
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,716
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Best way to send data from a GUI thread to a processing thread?

    Does this seem like a reasonable solution to anyone? I'd appreciate any comments at all.
    Reasonable - sure.
    But its hard to tell exactly without getting deeper in to the logic of your application.

    The only non related comment I have is that you are locking the mutex basically the hole run() duration, which is not good - it is legal, but it cause your application or parts of the logic to wait longer they they should/could.
    You should only mutex where data is accessed, and try to be as atomic as possible.
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

  7. The following user says thank you to high_flyer for this useful post:

    dmginc (27th January 2011)

  8. #7
    Join Date
    Jan 2010
    Posts
    18
    Thanks
    8
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Best way to send data from a GUI thread to a processing thread?

    Quote Originally Posted by high_flyer View Post
    Reasonable - sure.
    But its hard to tell exactly without getting deeper in to the logic of your application.

    The only non related comment I have is that you are locking the mutex basically the hole run() duration, which is not good - it is legal, but it cause your application or parts of the logic to wait longer they they should/could.
    You should only mutex where data is accessed, and try to be as atomic as possible.
    Thanks - I must point out that the slots (connected to signals triggered by the main window GUI) in the ProcessingThread are quite short and only copy a small amount of data. As I said before, my goal in using the mutexes is merely to make sure the update of the flags/settings is predictable and does not occur in the middle of processing. So it looks like the maximum penalty I would pay is a one iteration delay of run() in updating these flags/settings I guess...
    Would you agree?

    On a related note: When using mutexes to protect different data in the same thread, should I declare seperate mutexes?

    eg:
    Qt Code:
    1. void ProcessingThread::run()
    2. {
    3. while(1)
    4. {
    5. frame=grabFrame();
    6. mutex.lock();
    7. if(flag1)
    8. doProcessingOnFrame1(frame,setting1,setting2);
    9. if(flag2)
    10. doProcessingOnFrame2(frame,setting3,setting4);
    11. if(flag3)
    12. doProcessingOnFrame3(frame,setting5,setting6);
    13. mutex.unlock();
    14. emit newFrame(frame);
    15. mutex2.lock();
    16. updateFPSvalue(); // saves current FPS value in a private member (this member is accessed by the GUI thread using a "get" function containing a QMutexLocker)
    17. mutex2.unlock();
    18. }
    19. }
    To copy to clipboard, switch view to plain text mode 

    Thanks again.

  9. #8
    Join Date
    Jan 2006
    Location
    Munich, Germany
    Posts
    4,716
    Thanks
    21
    Thanked 418 Times in 411 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows

    Default Re: Best way to send data from a GUI thread to a processing thread?

    On a related note: When using mutexes to protect different data in the same thread, should I declare seperate mutexes?
    It depends.
    If it is allowed for various variables to be accessed from out side at the same time, you will need a mutex per such location.
    If only one access per time to any of the data in thread is allowed, then you can use one mutex (member).
    In your example one mutex is enough, since they are all in the same place.
    But if you had other methods that should allow parallel access to data, you might need more mutexes.

    Usually however, you only need one mutex, if you design correctly.
    ==========================signature=============== ==================
    S.O.L.I.D principles (use them!):
    https://en.wikipedia.org/wiki/SOLID_...iented_design)

    Do you write clean code? - if you are TDD'ing then maybe, if not, your not writing clean code.

Similar Threads

  1. Replies: 2
    Last Post: 30th December 2010, 21:38
  2. howto Processing GUI events until a thread exits
    By doggrant in forum Qt Programming
    Replies: 0
    Last Post: 5th October 2009, 15:50
  3. Replies: 6
    Last Post: 29th April 2009, 18:17
  4. Can you send a signal to a thread?
    By Dumbledore in forum Qt Programming
    Replies: 1
    Last Post: 9th November 2007, 20:31
  5. Thread+send event
    By Fastman in forum Qt Programming
    Replies: 20
    Last Post: 1st August 2007, 14:09

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.