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
    Qt products
    Qt4
    Platforms
    Unix/X11
    Thanks
    6

    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

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

    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.

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

    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.

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

    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.

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

    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?

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

    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 

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

    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?

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

    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?

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

    Default Re: QThread and QQueue

    I've tried it both ways and still no dice.

    The data is read every 64Hz, and has can recieve anywhere from 4 bytes of raw data to 512 bytes of raw data. The data is capture in an array of integer values, then copied into a QStringList, then emitted to the decoder. The Messager thread actually works faster then 64 Hz. The messager use to do the decoding at the same time, but I was having lots of slow downs and crashes.

    I figured putting the decoder into it's own thread, then having the messager send it packets to decode, then it would make the application more efficient.

    So the Messager fills the Decoder queue, then the Decoder decodes the data and emits a signal to the UI to update a particular GUI element. The Decoder queue could get backed up, considering the average length of a message is about 12-18 bytes.

    Why does the decoder thread stop working when the application gets minimized that really seems to be te issue.

    DeckSimulator, the UI, has the two objects, decoder and messager. They are started in the constructor of DeckSimulator, I'm running out of ideas. It doesn't fail when it stays non-minimized.

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

    Default Re: QThread and QQueue

    Quote Originally Posted by qball2k5
    The data is read every 64Hz, and has can recieve anywhere from 4 bytes of raw data to 512 bytes of raw data.
    Well 64 Hz is a bit too much for a single-threaded application.

    Quote Originally Posted by qball2k5
    DeckSimulator, the UI, has the two objects, decoder and messager. They are started in the constructor of DeckSimulator, I'm running out of ideas. It doesn't fail when it stays non-minimized.
    Which Qt version do you use? Anyway, I've checked the task tracker and I didn't found anything connected with this issue.

    Maybe you could prepare a minimal, compilable example that reproduces the problem (without all the GUI and decoding stuff, "messager" can send the same data all the time)? This way it will be easier to search for possible solutions.

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

    Default Re: QThread and QQueue

    I'm using 4.1.3

    I can see if I can rip out some of the sensitive things. I'm battling a crash right now.

    The application crashes when I switch between tabs....my GUI has tabs, each with lots of stuff on them, when I toggle between them, I get an index of range problem. I think I know why...it's a problem with my decoder.

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

    Default Re: QThread and QQueue

    Here's a compiled stripped down Messager. I connect the decoder to the PacketRecieved signal, then the decoder is connected to the GUI.

    messager.cpp
    Qt Code:
    1. #include <QMutexLocker>
    2. #include <QFile>
    3. #include <QTextStream>
    4. #include <QtDebug>
    5. #include <QStringList>
    6. #include <iostream>
    7. #include <QMetaType>
    8. #include <QTime>
    9.  
    10. #include "messager.h"
    11.  
    12. using std::cout;
    13.  
    14. Messager::Messager(QObject *parent)
    15. : QThread(parent)
    16. {
    17. stopped = false;
    18. abort = false;
    19. ReadDevice = false;
    20.  
    21. pollRate = 3;
    22. //Constructor
    23. }
    24.  
    25. Messager::~Messager()
    26. {
    27. //Destructor
    28. mutex.lock();
    29. waitCondition.wakeOne();
    30. mutex.unlock();
    31.  
    32. wait();
    33. }
    34.  
    35. void Messager::run()
    36. {
    37.  
    38. do
    39. {
    40. //This code is for sending a packet
    41. /* if(!packetQueue.isEmpty())
    42. {
    43. if(mutex.tryLock())
    44. {
    45. Packet sendPacket = packetQueue.dequeue();
    46. UINT8 address = addressQueue.dequeue();
    47. UPDATE type = typeQueue.dequeue();
    48.  
    49. mutex.unlock();
    50.  
    51. if(SendMessage(sendPacket, address))
    52. emit PacketSent(true, type);
    53. else
    54. emit PacketSent(false, type);
    55. }
    56. } */
    57.  
    58. msleep(pollRate);
    59.  
    60.  
    61. if(ReadDevice)
    62. ReadMessage(0);
    63.  
    64. if(abort)
    65. stopped = true;
    66.  
    67. }while(!stopped);
    68.  
    69. if(stopped)
    70. quit();
    71. else
    72. exec();
    73.  
    74. }
    75.  
    76. void Messager::stop()
    77. {
    78. stopped = true;
    79. }
    80.  
    81. /*void Messager::SendPacket(Packet myPacket, UINT8 address, UPDATE Type)
    82. {
    83.   QMutexLocker locker(&mutex);
    84.  
    85.   packetQueue.enqueue(myPacket);
    86.   addressQueue.enqueue(address);
    87.   typeQueue.enqueue(Type);
    88. }
    89.  
    90. bool Messager::Config(int port, int bitrate)
    91. {
    92.   QMutexLocker locker(&mutex);
    93.  
    94.   // Open the port
    95.   ahandle = aa_open(port);
    96.  
    97.   if (ahandle <= 0)
    98.   {
    99. return false;
    100.   }
    101.  
    102.   aa_configure(ahandle, AA_CONFIG_GPIO_I2C);
    103.   aa_i2c_pullup(ahandle, AA_I2C_PULLUP_BOTH);
    104.   aa_target_power(ahandle, AA_TARGET_POWER_NONE);
    105.  
    106.   // Set the bitrate
    107.   bitrate = aa_i2c_bitrate(ahandle, bitrate);
    108.  
    109.   return true;
    110. }
    111.  
    112. bool Messager::SendMessage(Packet outgoingPacket, UINT8 addr)
    113. {
    114.   QMutexLocker locker(&mutex);
    115.  
    116.   int status = 0;
    117.   int retries = 0;
    118.   UINT16 aacount;
    119.  
    120.   status = aa_i2c_write_ext(ahandle, addr, AA_I2C_NO_FLAGS, (2*outgoingPacket.GetLength())+4, outgoingPacket.GetData(), &aacount);
    121.  
    122.   if(status != 0) // Try again
    123.   {
    124. ++retries;
    125.  
    126. status = aa_i2c_write_ext(ahandle, addr, AA_I2C_NO_FLAGS, (2*outgoingPacket.GetLength())+4, outgoingPacket.GetData(), &aacount);
    127.  
    128. if(status != 0)
    129. {
    130. qDebug() << "Message Sending Failure!\n";
    131. return false;
    132. }
    133.  
    134. else
    135. return true;
    136.  
    137.   }
    138.   else
    139. return true;
    140. }*/
    141.  
    142. bool Messager::ReadMessage(int address)
    143. {
    144. QStringList packet;
    145. QString formatter;
    146. int i;
    147.  
    148. for(i = 0; i < 15; i ++)
    149. packet.append(formatter.number(0xFF));
    150.  
    151.  
    152. emit PacketRecieved( packet );
    153.  
    154. return true;
    155.  
    156. /* UINT8 buffer[511];
    157.   UINT16 actualSize = 0;
    158.   UINT8* curBuf = buffer;
    159.   UINT16 actualRead = 0;
    160.   INT32 status = 0;
    161.   UINT8 payloadSzWords = 0;
    162.   UINT16 curSize = 4;
    163.   UINT16 messageID = 0;
    164.   int i = 0;
    165.   int retries = 0;
    166.   int start = 0;
    167.   bool ok;
    168.  
    169.   status = aa_i2c_read_ext(ahandle, address, AA_I2C_NO_FLAGS, curSize, curBuf, &actualRead);
    170.  
    171.   if ((0 != status) )
    172.   {
    173. ++retries;
    174. status = aa_i2c_read_ext(ahandle, address, AA_I2C_NO_FLAGS, curSize, curBuf, &actualRead);
    175.   }
    176.   else if ( actualRead != curSize)
    177.   {
    178. return false;
    179.   }
    180.   else // the correct number of bytes were received
    181.   {
    182. payloadSzWords = curBuf[0];
    183. actualSize = actualRead;
    184.  
    185. if ( 0 != payloadSzWords )
    186. {
    187. curSize = 2 * (UINT16(payloadSzWords));
    188. actualSize += curSize;
    189. curBuf = &buffer[actualRead];
    190. status = aa_i2c_read_ext(ahandle, address, AA_I2C_NO_FLAGS, curSize, curBuf, &actualRead);
    191.  
    192. if ((0 != status))
    193. {
    194. ++retries;
    195. status = aa_i2c_read_ext(ahandle, address, AA_I2C_NO_FLAGS, curSize, curBuf, &actualRead);
    196. }
    197. else if ( actualRead != curSize)
    198. {
    199. status = -7;
    200. }
    201. else if(status ==0)
    202. {
    203. for(i = 0; i < actualSize; i++)
    204. {
    205. packet.append(formatter.sprintf("%02x ", buffer[i] & 0xff));
    206. }
    207.  
    208. emit PacketRecieved( packet );
    209. }
    210. else
    211. return false;
    212. }
    213. else
    214. return false;
    215.   }
    216.  
    217.   return true;*/
    218. }
    219.  
    220. void Messager::EnableDeviceStatus(bool Enabled)
    221. {
    222. mutex.lock();
    223. ReadDevice = Enabled;
    224. mutex.unlock();
    225. }
    To copy to clipboard, switch view to plain text mode 

    And here's messager.h

    Qt Code:
    1. #ifndef MESSAGER_H
    2. #define MESSAGER_H
    3.  
    4. #include <QThread>
    5. #include <QMutex>
    6. #include <QWaitCondition>
    7. #include <QQueue>
    8.  
    9. class Messager : public QThread
    10. {
    11. Q_OBJECT
    12.  
    13. public:
    14. Messager(QObject *parent = 0);
    15. ~Messager();
    16. void stop();
    17. void EnableDeviceStatus(bool Enabled);
    18.  
    19. signals:
    20. //void PacketSent(bool Success, UPDATE changeUI);
    21. void PacketRecieved(const QStringList &packet);
    22.  
    23. public slots:
    24. //void SendPacket(Packet myPacket, UINT8 address, UPDATE MessageType);
    25.  
    26. protected:
    27. void run();
    28.  
    29. private:
    30. //bool SendMessage(Packet outgoingPacket, UINT8 address);
    31. bool ReadMessage(int address);
    32.  
    33. /* QQueue <Packet> packetQueue;
    34. QQueue <UINT8> addressQueue;
    35. QQueue <UPDATE> typeQueue;
    36. UPDATE MessageType;
    37. UINT8 addr;
    38.  
    39. Aardvark ahandle;
    40.  
    41. */
    42. volatile bool stopped;
    43. bool abort;
    44. int pollRate;
    45.  
    46. bool ReadDevice;
    47.  
    48. QMutex mutex;
    49. QWaitCondition waitCondition;
    50.  
    51. };
    52.  
    53. #endif
    To copy to clipboard, switch view to plain text mode 

    There you go, do you want a striped down decoder too?

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
  •  
Qt is a trademark of The Qt Company.