Page 1 of 2 12 LastLast
Results 1 to 20 of 21

Thread: Accessing data from a worker thread

  1. #1
    Join Date
    May 2007
    Posts
    301
    Thanks
    46
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Accessing data from a worker thread

    Hi,

    I have a thread which accesses a data structure which is held in a different class. The thread modifies this data. The main gui thread then uses this data structure to populate a list. Things are fine for some time but then the application crashes. I'm guessing this is a threading issue?

    What is the 'safe' way of accessing 'shared' data from one thread to another?

    Kind regards,
    Steve

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Accessing data from a worker thread

    Synchronise access to the data using mutexes (QMutex).

  3. #3
    Join Date
    May 2007
    Posts
    301
    Thanks
    46
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Accessing data from a worker thread

    Thanks for that, this is what I've been trying, when each are using the data I put a mutex.lock() and then mutex.unlock() when they finished using the data, still getting a crash. Defo a thread issue, as it is random times, debug window doesn't show me where crash is

    If I pass QString's from the thread, then all is fine ( the data structure I mentioned before just had three QString's ). The QString's are created in the worker thread though and I guess in the main thread they will be copies?

    Regards,
    Steve

  4. #4
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Accessing data from a worker thread

    Guard it with a QMutex or a QReadWriteLock.
    Read about these two Qt classes in Assistant to get an idea about how are they used.

    Regards

  5. #5
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Accessing data from a worker thread

    Hmm... Aren't QStrings thread-safe? Could we see your code?

  6. #6
    Join Date
    May 2007
    Posts
    301
    Thanks
    46
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Accessing data from a worker thread

    I guess they are.

    This is the function which gets called after the thread has changed the data ( m_can[i] ), the thread emits scrolltable function which ends up calling the code below:

    Qt Code:
    1. void DATreeModel::setCanData( int nAmount, int nCount )
    2. {
    3. int row = rowCount();
    4.  
    5. beginInsertRows(QModelIndex(), row, row + nAmount - 1 ); // insert nAmount of rows
    6.  
    7. QMutex mutex;
    8. mutex.lock();
    9.  
    10. for( int i = 0; i < nAmount; i++ )
    11. {
    12. m_Data.append(m_can[i].strId);
    13. m_Data.append(m_can[i].strTime);
    14. m_Data.append(m_can[i].strData);
    15. QString strCount;
    16. strCount.sprintf( "%i", nCount );
    17. m_Data.append(strCount);
    18. nCount++;
    19.  
    20. }
    21. mutex.unlock();
    22.  
    23. endInsertRows();
    24. }
    To copy to clipboard, switch view to plain text mode 

    This is the thread code :

    Qt Code:
    1. void CanRead::run()
    2. {
    3. m_nCount = 0;
    4.  
    5. m_bCancelled = false;
    6. unsigned long nMsgAmount = 1;
    7.  
    8. QString szTemp = "";
    9. unsigned int iCanId = 0;
    10.  
    11. QString strCanId = "";
    12. QString strData = "";
    13.  
    14. QMutex mutex;
    15.  
    16. while( !m_bCancelled )
    17. {
    18. #ifdef __CANON_
    19. unsigned long numMsgs = 1;
    20. PASSTHRU_MSG *pRxMsg = NULL;
    21. pRxMsg = theApp->GetMessageDetail( &numMsgs, 0 );
    22. nMsgAmount = numMsgs; // store amount of messages we got
    23.  
    24. strData = "";
    25.  
    26. int index = 0;
    27. // Read can data, store in buffer ( read say N amount and then emit? )
    28. while ( numMsgs && !m_bCancelled )
    29. {
    30. mutex.lock();
    31. szTemp = "";
    32. m_can[index].strData = "";
    33. iCanId = 0;
    34. for ( int iLoop = 0; iLoop < 4; iLoop++)
    35. {
    36. iCanId = (iCanId << 8 ) | pRxMsg->Data[iLoop];
    37. }
    38.  
    39. QString strId;
    40. strId.sprintf( "%d", iCanId );
    41. strCanId = strId;
    42.  
    43.  
    44. QString strName = theApp->m_dcb.GetMessageName( strId );
    45. if( strName != "" )
    46. m_can[index].strId = strName;
    47. else
    48. {
    49. if( pRxMsg->RxStatus & 0x100 )
    50. {
    51. m_can[index].strId.sprintf( "%X X", iCanId);
    52. strCanId.sprintf( "%X X", iCanId );
    53. }
    54. else
    55. {
    56. m_can[index].strId.sprintf( "%03X", iCanId);
    57. strCanId.sprintf( "%03X", iCanId );
    58. }
    59. }
    60.  
    61. for ( int iLoop = 4; (unsigned)iLoop < (pRxMsg->DataSize ); iLoop++)
    62. {
    63. szTemp.sprintf("%02X ", pRxMsg->Data[iLoop]);
    64. m_can[index].strData += szTemp;
    65. strData += szTemp;
    66. }
    67.  
    68. m_can[index].strTime.sprintf("%04d", pRxMsg->Timestamp);
    69.  
    70. numMsgs--;
    71.  
    72. m_nCount++;
    73.  
    74. mutex.unlock();
    75.  
    76. } // end while ( ulNoMsgs )
    77.  
    78.  
    79. #else // some dummy data for testing
    80. QString strId = theApp->m_dcb.GetMessageName( "1911" );
    81. if( strId != "" )
    82. m_can[0].strId = strId;
    83. else
    84. m_can[0].strId = "0xfea";
    85.  
    86. m_can[0].strData = "222222222222";
    87. m_can[0].strTime = "----";
    88.  
    89. m_nCount += nMsgAmount;
    90.  
    91. strCanId = "1911";
    92. strData = "2222222222";
    93. #endif
    94. // send out signal
    95. if( nMsgAmount > 0 )
    96. emit scrolltable( m_nCount - 2, nMsgAmount );
    97. msleep(10);
    98.  
    99. } // end while ( true )
    100.  
    101. }
    To copy to clipboard, switch view to plain text mode 

    Kind regards,
    Steve

  7. #7
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Accessing data from a worker thread

    What is the relation between m_can from the worker thread and the one from the GUI thread?

  8. #8
    Join Date
    May 2007
    Posts
    301
    Thanks
    46
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Accessing data from a worker thread

    Hi Marcel,

    The m_can structure is defined now in a header file and declared globally through out the application, use to be declared in the derived QMainWindow class.

    The structure is :

    Qt Code:
    1. #define __CANDATA
    2.  
    3. struct CANDATA
    4. {
    5. QString strId;
    6. QString strTime;
    7. QString strData;
    8. };
    9.  
    10. #endif
    11.  
    12. extern CANDATA m_can[2];
    To copy to clipboard, switch view to plain text mode 

    And is declared externally.

    Regards,
    Steve

  9. #9
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Accessing data from a worker thread

    I see that the structure array has only 2 elements.
    Are you sure that nAmount doesn't come > 2 from the thread?

  10. #10
    Join Date
    May 2007
    Posts
    301
    Thanks
    46
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Accessing data from a worker thread

    100% sure

    The crash appears to be in QtCored4.dll with some heap problem?


    Crash is in the following function :

    Qt Code:
    1. void __cdecl _free_base (void * pBlock)
    To copy to clipboard, switch view to plain text mode 

    Found in free.c

    line crash is on :

    Qt Code:
    1. retval = HeapFree(_crtheap, 0, pBlock);
    To copy to clipboard, switch view to plain text mode 

    I'm at a loss, but like I said in previous posts, if I just pass QString's back as opposed to structure, all is fine...

    Regards,
    Steve
    Last edited by steg90; 25th May 2007 at 08:13.

  11. #11
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Accessing data from a worker thread

    Anyway, you're using that mutex wrong.

    You should create static getters and setters for that structure, and guard it with a mutex in there.

    You're guarding entire portions of code right now.
    I'm not saying this is the problem, but you should revise your code.

    The problem could be that you emit that signal from a while loop.
    They could be posted very fast/often in the GUI event loop, and maybe this is the reason it crashes.
    Couldn't you queue the data that comes from the thread and apply it sequentially?

  12. #12
    Join Date
    May 2007
    Posts
    301
    Thanks
    46
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Accessing data from a worker thread

    Thanks Marcel,

    They are posted fast.

    Are you saying to do something like this for the mutex :

    Qt Code:
    1. struct CANDATA
    2. {
    3. QString strId;
    4. QString strTime;
    5. QString strData;
    6.  
    7. QMutex m_Mutex;
    8.  
    9. public:
    10. static QString getId() { return strId; }
    11. static QString getTime() { return strTime; }
    12. static QString getData() { return strData; }
    13.  
    14. static void setId( QString id ) { m_Mutex.lock(); strId = id; m_Mutex.unlock();}
    15. static void setTime( QString time ) { m_Mutex.lock(); strTime = time; m_Mutex.unlock();}
    16. static void setData( QString data ) { m_Mutex.lock(); strData = data;m_Mutex.unlock(); }
    17.  
    18. };
    To copy to clipboard, switch view to plain text mode 

    Regards,
    Steve

  13. #13
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Accessing data from a worker thread

    Yes, something like that, but keep in mind that a mutex can slow down things considerably.
    You should make only one setter, with three parameters, and set all three members at once.

    Regards

  14. #14
    Join Date
    May 2007
    Posts
    301
    Thanks
    46
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Accessing data from a worker thread

    Thanks for that Marcel, I appreciate your help.

    Regards,
    Steve

  15. #15
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: Accessing data from a worker thread

    Hmm, that will still allow reading and writing same time which is not safe (only concurrent writes are protected). I'd suggest using QReadLocker and QWriteLocker. Usage is extremely simple and it will allow both threads reading the values same time.
    J-P Nurmi

  16. The following user says thank you to jpn for this useful post:

    steg90 (25th May 2007)

  17. #16
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Accessing data from a worker thread

    The mutex used in the first suggestion doesn't make sense. You create a local mutex and destroy it in the same method which means each call to the method creates a separate mutex, so there is no synchronisation.

    @Marcel: Mutexes in Qt are extremely fast, so there won't be any noticable slowdown, provided that any thread doesn't hold the mutex longer than necessary.

  18. #17
    Join Date
    Feb 2006
    Location
    Romania
    Posts
    2,744
    Thanks
    8
    Thanked 541 Times in 521 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Accessing data from a worker thread

    Mutexes in Qt are extremely fast, so there won't be any noticable slowdown, provided that any thread doesn't hold the mutex longer than necessary
    I know.
    He had three setters and in each one of them he was locking/unlocking the mutex.
    He was calling the methods one after another anyway, so I suggested combining them in a single method with only one lock.unlock.

  19. #18
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Accessing data from a worker thread

    Yes, you are right, of course. Using a read-write lock would speed up things even more without compromising safety.
    Qt Code:
    1. class CANDATA
    2. // note "class" instead of "struct" here as structs are by default public
    3. {
    4. QString strId;
    5. QString strTime;
    6. QString strData;
    7. QReadWriteLock m_Mutex;
    8. public:
    9. QString getId() { QReadLocker(&m_Mutex); return strId; }
    10. QString getTime() { QReadLocker(&m_Mutex); return strTime; }
    11. QString getData() { QReadLocker(&m_Mutex); return strData; }
    12.  
    13. void setId( QString id ) { QWriteLocker(&m_Mutex); strId = id; }
    14. void setTime( QString time ) { QWriteLocker(&m_Mutex); strTime = time; }
    15. void setData( QString data ) { QWriteLocker(&m_Mutex); strData = data;}
    16. void setAll(const QString &id, const QString &time, const QString &data){
    17. QWriteLocker(&m_Mutex);
    18. strId = id; strTime = time; strData = data;
    19. }
    20. };
    To copy to clipboard, switch view to plain text mode 

    BTW. Statics didn't make sense here, so I removed them.

  20. #19
    Join Date
    May 2007
    Posts
    301
    Thanks
    46
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Accessing data from a worker thread

    Thanks guys,

    I also removed the statics, and used the QReadLocker and QWriteLocker and all is now well.

    Thank you all for your input and solutions

    BTW, this is what my structured finished as :

    Qt Code:
    1. struct CANDATA
    2. {
    3. QString strId;
    4. QString strTime;
    5. QString strData;
    6. QReadWriteLock m_lock;
    7. public:
    8. QString getId() { QReadLocker locker(&m_lock); return strId; }
    9. QString getTime() { QReadLocker locker(&m_lock); return strTime; }
    10. QString getData() { QReadLocker locker(&m_lock); return strData; }
    11. void setData( QString id, QString time, QString data )
    12. {
    13. m_lock.lockForWrite();
    14. strId = id;
    15. strTime = time;
    16. strData = data;
    17. m_lock.unlock();
    18. }
    19. };
    To copy to clipboard, switch view to plain text mode 
    Kind regards,
    Steve
    Last edited by steg90; 25th May 2007 at 09:50.

  21. #20
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,519 Times in 1,389 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: Accessing data from a worker thread

    Default visibility of a struct is public (as wysota's comment mentions) so one can still accidentally access the members directly without using getters/setters.
    J-P Nurmi

Similar Threads

  1. QTableView : accessing the data
    By marvaneke in forum Newbie
    Replies: 10
    Last Post: 30th March 2012, 11:31
  2. KDE/QWT doubt on debian sarge
    By hildebrand in forum KDE Forum
    Replies: 13
    Last Post: 25th April 2007, 06:13
  3. Replies: 10
    Last Post: 20th March 2007, 22:19
  4. speed of setdata - lots of items in treeview
    By Big Duck in forum Qt Programming
    Replies: 4
    Last Post: 6th July 2006, 12:53
  5. Replies: 2
    Last Post: 6th January 2006, 21:15

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.