Results 1 to 20 of 20

Thread: QThread and QQueue

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Mar 2006
    Posts
    26
    Thanks
    6
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default QThread and QQueue

    Hey!

    I have an application that has three thread.

    Thread One: GUI
    Thread Two: Messeger, comminicated with a device using an Aardvark (I2C bus)
    Thread Three: Decoder, decodes the data from the Messeger, sends it to UI

    The problem is that the Decoder seems to have a tendency to stop working, but I don't ever tell it to stop. I can see that the Messeger continuing to send data to te Decoder, but the decoder doesn't process it. Here's how the decoder thread looks.

    Qt Code:
    1. Decoder::Decoder(QObject *parent)
    2. : QThread(parent)
    3. {
    4. stopped = false;
    5. abort = false;
    6. }
    7.  
    8. Decoder::~Decoder()
    9. {
    10. mutex.lock();
    11. waitCondition.wakeOne();
    12. mutex.unlock();
    13.  
    14. wait();
    15. }
    16.  
    17. void Decoder::run()
    18. {
    19. do
    20. {
    21. mutex.lock();
    22. if (decodeQueue.isEmpty())
    23. waitCondition.wait(&mutex);
    24. mutex.unlock();
    25.  
    26. if(mutex.tryLock())
    27. {
    28. QStringList packet = decodeQueue.dequeue();
    29. mutex.unlock();
    30.  
    31. Decode(packet);
    32. }
    33.  
    34. msleep(2);
    35.  
    36. }while(!stopped);
    37.  
    38. if(stopped)
    39. quit();
    40. else
    41. exec();
    42. }
    43.  
    44. void Decoder::stop()
    45. {
    46. stopped = true;
    47. }
    48.  
    49. void Decoder::DecodePacket( const QStringList &packet )
    50. {
    51. mutex.lock();
    52. decodeQueue.enqueue(packet);
    53. waitCondition.wakeOne();
    54. mutex.unlock();
    55. }
    56.  
    57. void Decoder::Decode( QStringList packet )
    58. {
    59. //Decodes packet and emits data to the GUi
    60. }
    To copy to clipboard, switch view to plain text mode 

    Any ideas?

    Thanks.

    Rob

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread and QQueue

    Quote Originally Posted by qball2k5
    Qt Code:
    1. void Decoder::run()
    2. {
    3. ...
    4. if(stopped)
    5. quit();
    6. else
    7. exec();
    8. }
    To copy to clipboard, switch view to plain text mode 
    This part is a bit weird.

    Quote Originally Posted by qball2k5
    Decodes packet and emits data to the GUi
    Are you sure that you use queued connection for this? Decoder object lives in a thread that created it, while Decoder::run() lives in a new thread --- this will fool automatic connections.

    I'm not sure why do you unlock mutex just to try to lock it again.
    Qt Code:
    1. Decoder::~Decoder()
    2. {
    3. stopped = true;
    4.  
    5. mutex.lock();
    6. waitCondition.wakeOne();
    7. mutex.unlock();
    8.  
    9. wait();
    10. }
    11.  
    12. Decoder::run()
    13. {
    14. while( ! stopped ) {
    15. mutex.lock();
    16.  
    17. while( decodeQueue.isEmpty() && ! stopped ) {
    18. waitCondition.wait( &mutex );
    19. }
    20.  
    21. if( ! stopped ) {
    22. QStringList packet = decodeQueue.dequeue();
    23. }
    24.  
    25. mutex.unlock();
    26.  
    27. if( ! stopped ) {
    28. Decode( packet );
    29. }
    30. }
    31. }
    To copy to clipboard, switch view to plain text mode 

  3. #3
    Join Date
    Mar 2006
    Posts
    26
    Thanks
    6
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QThread and QQueue

    I'm definately using a queued connection, I set that up for all my signals.

    This is the slot that recieves the QStringList from the messager

    Qt Code:
    1. void Decoder::DecodePacket( const QStringList &packet )
    2. {
    3. mutex.lock();
    4. decodeQueue.enqueue(packet);
    5. waitCondition.wakeOne();
    6. mutex.unlock();
    7. }
    To copy to clipboard, switch view to plain text mode 

    In your example, won't the mutex be locked so this will never be able to add a new packet into the queue? Or am I missing something?

    As for the wierd part, I don't know why I put that there, thought I needed it. It was in one of the examples.

  4. #4
    Join Date
    Mar 2006
    Posts
    26
    Thanks
    6
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QThread and QQueue

    You know what....it works much better. I have another thread question though.

    My application right now is using like 85% of the CPU. I know it's because my messager thread. The messager thread basically has a queue of outgoing messages and if a message needs to be sent, it sends it. Then it checks to see if it needs to read data from the Aardvark (I2C). If it does, it reads it then passes it to the Decoder.

    Here's how it looks. It works, just not very efficieintly. Any ideas?

    Qt Code:
    1. Messager::~Messager()
    2. {
    3. //Destructor
    4. mutex.lock();
    5. waitCondition.wakeOne();
    6. mutex.unlock();
    7.  
    8. wait();
    9. }
    10.  
    11. void Messager::run()
    12. {
    13.  
    14. do
    15. {
    16. if(!packetQueue.isEmpty())
    17. {
    18. if(mutex.tryLock())
    19. {
    20. Packet sendPacket = packetQueue.dequeue();
    21. UINT8 address = addressQueue.dequeue();
    22. UPDATE type = typeQueue.dequeue();
    23.  
    24. mutex.unlock();
    25.  
    26. if(SendMessage(sendPacket, address))
    27. emit PacketSent(true, type);
    28. else
    29. emit PacketSent(false, type);
    30. }
    31. }
    32.  
    33. msleep(pollRate);
    34.  
    35. if(ReadDevice1)
    36. ReadMessage(D1_ADDRESS);
    37.  
    38.  
    39. if(ReadDevice2)
    40. ReadMessage(D2_ADDRESS);
    41.  
    42.  
    43. if(ReadDevice3)
    44. ReadMessage(D3_ADDRESS);
    45.  
    46.  
    47. if(ReadDevice4)
    48. ReadMessage(D4_ADDRESS);
    49.  
    50.  
    51. if (ReadDevice5)
    52. ReadMessage(D5_ADDRESS);
    53.  
    54. if(ReadDevice6)
    55. ReadMessage(D6_ADDRESS);
    56.  
    57.  
    58. if(abort)
    59. stopped = true;
    60.  
    61. }while(!stopped);
    62.  
    63. if(stopped)
    64. quit();
    65. else
    66. exec();
    67.  
    68. }
    69.  
    70. void Messager::SendPacket(Packet myPacket, UINT8 address, UPDATE Type)
    71. {
    72. QMutexLocker locker(&mutex);
    73.  
    74. packetQueue.enqueue(myPacket);
    75. addressQueue.enqueue(address);
    76. typeQueue.enqueue(Type);
    77. }
    78.  
    79. bool Messager::Config(int port, int bitrate)
    80. {
    81. //Configure I2C device
    82. }
    83.  
    84. bool Messager::SendMessage(Packet outgoingPacket, UINT8 addr)
    85. {
    86. //Write packet to I2C bus
    87. }
    88.  
    89. bool Messager::ReadMessage(UINT8 address)
    90. {
    91. //Read data from I2C bus, emit PacketRecieved signal to Decoder
    92. }
    93.  
    94. void Messager::EnableDevice1Status(bool Enabled)
    95. {
    96. mutex.lock();
    97. ReadDevice1 = Enabled;
    98. mutex.unlock();
    99. }
    To copy to clipboard, switch view to plain text mode 

    It needs to read only when told to and send any message that gets put into the queue. I'm still new to threads. I'd really appreciate any ideas.

    If this is confusing, I can attempt to elaborate better.

    Thanks,

    Rob

  5. #5
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread and QQueue

    Quote Originally Posted by qball2k5
    My application right now is using like 85% of the CPU. I know it's because my messager thread. The messager thread basically has a queue of outgoing messages and if a message needs to be sent, it sends it. Then it checks to see if it needs to read data from the Aardvark (I2C). If it does, it reads it then passes it to the Decoder.
    Sounds like it's a job for QSocketNotifier.

    To avoid problems, IMO, you should split the implementation into two classes: Messenger and MessengerThread.

    MessengerThread should look like this:
    Qt Code:
    1. void MessengerThread::run()
    2. {
    3. Messenger m;
    4. // setup connections or whatever
    5. exec();
    6. }
    To copy to clipboard, switch view to plain text mode 
    while Messenger (derived from QObject) should use QSocketNotifiers to monitor the devices.

    Of course you can do this using a single class, but you must watch out for connection types.

  6. #6
    Join Date
    Mar 2006
    Posts
    26
    Thanks
    6
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QThread and QQueue

    So....

    I'm starting the two threads from the GUI thread, called DeckSimulator.

    I call:

    Qt Code:
    1. messager.start(QThread::TimeCriticalPriority);
    2. decoder.start(QThread::LowPriority);
    To copy to clipboard, switch view to plain text mode 

    in the constructor of DeckSimulator

    That's starts them on there own thread. Right? Or do I need to start the thread when I call SendPacket(from Messager) and DecodePacket(from Decoder). Like in the Mandalbrot example.

  7. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread and QQueue

    Quote Originally Posted by qball2k5
    That's starts them on there own thread. Right?
    Yes, but only the run() method will be in a new thread. messager and decoder objects will live in the GUI thread, as you instantiate them before the new thread is created.

    Quote Originally Posted by qball2k5
    Or do I need to start the thread when I call SendPacket(from Messager) and DecodePacket(from Decoder). Like in the Mandalbrot example.
    No, you don't have to.

  8. #8
    Join Date
    Mar 2006
    Posts
    26
    Thanks
    6
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QThread and QQueue

    Sounds like it's a job for QSocketNotifier.
    It's really just one device, the Aardvark device, but different address to read using that device.

    It still looks like it locks up after a while and doesn't work. Could this be a stack issue?

    It just stops decoding, even though I can see the reads being done. I see the packet signal getting emitted and the DecodePacket slot getting called by that emitted signal, via breakpoints...i put breakpoints in the run function and it's not doing anything. the Run function isn't going, but the stopped variable is false, so it should continue to run.

    Any ideas?

  9. #9
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread and QQueue

    Quote Originally Posted by qball2k5
    It's really just one device, the Aardvark device, but different address to read using that device.
    It doesn't matter how many devices you have, QSocketNotifier should notify you when there is something to read, but of course you need a file descriptor for this.

    Quote Originally Posted by qball2k5
    It just stops decoding, even though I can see the reads being done.
    How about these?
    Qt Code:
    1. Decoder::~Decoder()
    2. {
    3. waitCondition.wakeOne();
    4. wait();
    5. }
    6.  
    7. void Decoder::DecodePacket( const QStringList &packet )
    8. {
    9. mutex.lock();
    10. decodeQueue.enqueue(packet);
    11. mutex.unlock();
    12.  
    13. waitCondition.wakeOne();
    14. }
    To copy to clipboard, switch view to plain text mode 

  10. #10
    Join Date
    Mar 2006
    Posts
    26
    Thanks
    6
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: QThread and QQueue

    It only seems to happen when I minimize it and the bring it back?

    Do I need to do something special for this?

  11. #11
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread and QQueue

    Quote Originally Posted by qball2k5
    It only seems to happen when I minimize it and the bring it back?
    Are you sure that signal/slot connections between decoder and reader threads are direct? If not, all data will go through GUI thread's event loop.

    Anyway, how much data you receive from that device? Maybe you don't need 3 threads for this?

  12. #12
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QThread and QQueue

    Quote Originally Posted by qball2k5
    I'm definately using a queued connection, I set that up for all my signals.

    This is the slot that recieves the QStringList from the messager
    When you use queued connections, signals behave like events that are delivered to event loop that runs in a thread that owns the receiver.

    There are two problems:
    • your thread doesn't have a running event loop (and it doesn't have to), so you can't use queued connections to send signals to objects that live inside it. You have to use direct connections, but with proper locking mechanism to avoid problems.
    • Decoder was created in the GUI thread, so all events (including those that realize queued connections) will go through the event loop in the GUI thread. If you block the GUI, you will also block the Decoder.


    In other words, try using a direct connection when you connect to Decoder::DecodePacket() (but Decoder should be still connected to the GUI using queued connection).

    Quote Originally Posted by qball2k5
    In your example, won't the mutex be locked so this will never be able to add a new packet into the queue?
    No, it shouldn't. QWaitCondition::wait() unlocks the mutex, waits and locks it again.

    Quote Originally Posted by qball2k5
    As for the wierd part, I don't know why I put that there, thought I needed it. It was in one of the examples.
    You exit the while loop only when stopped == true, so the else clause is never executed.

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.