Results 1 to 10 of 10

Thread: GUI with worker thread, signal/slot communication elaboration

  1. #1
    Join Date
    Apr 2012
    Posts
    38
    Thanks
    6
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Windows

    Default GUI with worker thread, signal/slot communication elaboration

    Hello All,

    I made a data acquisition software with the worker/DAQ code in one thread and the visualization/GUI in the other. My approach is using this method. I'm trying to communicate between these threads using signal/slot connections by emitting a void dataUpdate(unsigned char *buf); from the worker thread and visualizing the data in the GUI thread.

    The problem is that I'm not using any mutex whatsoever and I'm quite certain that the same memory gets accessed by both the threads at the same time, thus displaying bogus poo in my graph every few frames.

    I want to implement a QMutex or QSemaphore of some sort, although I'm a bit apprehensive about threads waiting for one another. Under no circumstance do I want the worker (acquisition) thread to be waiting to have write access to the variable, because if the DAQ thread starts waiting for GUI, I start losing data.

    My approach is different to the mandelbrot example due to the fact that the data processing gets done in the GUI, while the DAQ thread focuses solely on acquisition. Example:

    Qt Code:
    1. class myDAQ : public QObject{ //this is the one that should have no dead time
    2. public:
    3. myDAQ(){
    4. /*constructor stuff here*/
    5. buff=new unsigned char[2048];
    6. }
    7.  
    8. public slots:
    9. void acquireData(){
    10. //get the data;
    11. emit sendToBeGraphed(buff);
    12. }
    13.  
    14. signals:
    15. void sendToBeGraphed(unsigned char *buf);// usually a few thousand bytes worth of data
    16.  
    17. private:
    18. unsigned char *buff;
    19. };
    20.  
    21. class myGUI : public QMainWindow{
    22. public:
    23. myGUI(){
    24. thread=new QThread;
    25. acquisitionClass=new myDAQ;
    26.  
    27. connect(acquisitionClass,SIGNAL(sendToBeGraphed(unsigned char*)),this,SLOT(visProc(unsigned char*)));
    28.  
    29. acquisitionClass->moveToThread(thread);
    30. thread->start();
    31. }
    32.  
    33. public slots:
    34. void visProc(unsigned char *raw){
    35. decodeData();
    36. plotData();
    37. }
    38.  
    39. private:
    40. QThread *thread;
    41. myDAQ *acquisitionClass;
    42.  
    43. }
    To copy to clipboard, switch view to plain text mode 

    How do I ensure that when visProc() gets called, the buff variable is not being modified? I was thinking to mutex.lock() inside the myDAQ::acquireData(), but would I have to mutex.lock() in the GUI class as well?

    Thanks


    Regards,
    Mr_Cloud

  2. #2
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: GUI with worker thread, signal/slot communication elaboration

    The easiest way is of course to not use the same buffer.
    E.g. copy the data before emitting it.

    Cheers,
    _

  3. #3
    Join Date
    Apr 2012
    Posts
    38
    Thanks
    6
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: GUI with worker thread, signal/slot communication elaboration

    I get what you mean, but does the data have to be dynamically allocated for that to work? 'Cause then there's no point. (Only a pointer, har har har derp derp)

    I've had trouble communicating between threads if I didn't emit pointers to data, or single values. So for example declaring unsigned int buff[2048]; emit sendToBeGraphed(buff); would not be processed by visProc() in the other thread/class. Instead, only unsigned char *buff=new unsigned char[2048]; would.

    I've also tried emitting QStrings but I was never successful and the program would usually crash. Am I missing something trivial? Thanks
    Last edited by Mr_Cloud; 7th May 2014 at 06:06. Reason: Included stupid pun in brackets

  4. #4
    Join Date
    Mar 2008
    Location
    Kraków, Poland
    Posts
    1,536
    Thanked 284 Times in 279 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: GUI with worker thread, signal/slot communication elaboration

    Use QByteArray instead of unsigned char[] or QString.

  5. #5
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: GUI with worker thread, signal/slot communication elaboration

    Quote Originally Posted by Mr_Cloud View Post
    I get what you mean, but does the data have to be dynamically allocated for that to work? 'Cause then there's no point.
    You already do allocate the array dynamically
    Qt Code:
    1. buff=new unsigned char[2048];
    To copy to clipboard, switch view to plain text mode 
    As Lesiok said, QByteArray is usually a nicer way of doing that, especially if you want to copy

    Qt Code:
    1. QByteArray copyOfBuff = buff;
    2. copyOfBuff.detach(); // create deep copy
    3. emit sendToBeGraphed(copyOfBuff);
    To copy to clipboard, switch view to plain text mode 

    Cheers,
    _

  6. #6
    Join Date
    Apr 2012
    Posts
    38
    Thanks
    6
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: GUI with worker thread, signal/slot communication elaboration

    Hey guys,

    Thank you for your response. I can confirm that QByteArray is a working means of communication between threads (as expected). I wonder however why I haven't had any luck with QVector...

    Anyway it appears that now I'll have to deal with multiple types of data to transfer between threads: double, char, string/QString etc. and I have found this resource to split strings using delimiter characters. The code is

    Qt Code:
    1. vector<string> split(string str, string delim)
    2. {
    3. unsigned start = 0;
    4. unsigned end;
    5. vector<string> v;
    6.  
    7. while( (end = str.find(delim, start)) != string::npos )
    8. {
    9. v.push_back(str.substr(start, end-start));
    10. start = end + delim.length();
    11. }
    12. v.push_back(str.substr(start));
    13. return v;
    14. }
    To copy to clipboard, switch view to plain text mode 

    Previously, I created a commWrapper class which just contained all the different types of variables I need to transfer between threads and I would emit newData(commWrapper*); and connect it to the recipient thread, but that seemed to crash or unexpectedly exit a lot.

    Qt Code:
    1. class commWrapper
    2. {
    3. public:
    4. double a,b,c;
    5. string derp,hurr;
    6. };
    7.  
    8. //usage
    9. commWrapper *hai=new commWrapper;
    10. hai->a=69;
    11. hai->derp="lol this is a terrible example";
    12.  
    13. emit newData(hai);
    To copy to clipboard, switch view to plain text mode 

    It is worth to note that emitting a non-pointer version of commWrapper - aka, emitting newData(commWrapper); instead of newData(commWrapper*); - would not work at all and thread communication was non-existent.

    Now I'm thinking that I am going to emit a QByteArray with comma-delimited data and just process it in the recipient thread with the split() function above. Hopefully that will eradicate crashes. Thoughts?

  7. #7
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: GUI with worker thread, signal/slot communication elaboration

    I think the correct way in this case would be to use a non-pointer to commWrapper.
    In order to make that work across threads, you'll have to declare commWrapper as a Qt meta type.
    http://qt-project.org/doc/qt-4.8/qmetatype.html

    Basically you add a macro to the header that declares commWrapper and call qRegisterMetaType<commWrapper>() in main() and you are good.

    Cheers,
    _

  8. The following user says thank you to anda_skoa for this useful post:

    Mr_Cloud (18th May 2014)

  9. #8
    Join Date
    Apr 2012
    Posts
    38
    Thanks
    6
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: GUI with worker thread, signal/slot communication elaboration

    Awesome, that seems to have done it! Thank you, anda_skoa. Funnily enough, the comma-delimited QByteArray approach was in no way stable by the time I implemented your solution above.

    I've qRegister'dMetaType the commWrapper before instantiating my objects or threads and tested heavily. No crashes thus far. Winrar.7z

    Oh programming, why art thou such a heartless butch sometimes..

    ..Feel free to leisurely interchange "programming" with "Mr_Cloud's Qt/C++ knowledge" on the previous line lol

    Edit: Should I add the registerMetaType in the main.cpp before return app.exec()? I currently have it in my constructor for the main class with all the UI stuff. Does it matter where it gets declared?
    Last edited by Mr_Cloud; 18th May 2014 at 17:54.

  10. #9
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: GUI with worker thread, signal/slot communication elaboration

    You don't need to put it into main(), the constructor of your main class is OK as well.

    It just needs to be called before the cross-thread connection is created (well, actually used).

    Cheers,
    _

  11. #10
    Join Date
    Apr 2012
    Posts
    38
    Thanks
    6
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: GUI with worker thread, signal/slot communication elaboration

    Yep awesome. Thanks!

Similar Threads

  1. Thread signal/slot problem
    By K4ELO in forum Qt Programming
    Replies: 4
    Last Post: 1st January 2013, 14:34
  2. slot in worker thread is not called
    By phenoboy in forum Qt Programming
    Replies: 1
    Last Post: 2nd June 2012, 20:45
  3. Signal not found / thread communication
    By ruehlchr in forum Qt Programming
    Replies: 4
    Last Post: 2nd November 2010, 06:23
  4. Replies: 9
    Last Post: 28th November 2009, 21:31
  5. Main thread - worker thread communication.
    By kikapu in forum Newbie
    Replies: 25
    Last Post: 23rd May 2007, 23: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.