Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Blocking Queue Between QThreads

Blocking Queue Between QThreads

Scheduled Pinned Locked Moved Solved General and Desktop
multi-threadingblocking queuesignal & slot
6 Posts 4 Posters 4.7k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    podkiva
    wrote on last edited by
    #1

    Hello everyone,

    Suppose I have an application with two threads, first one (producer) produces some custom messages (a-ka commands with some additional data), while the second one (executor) is responsible for executing these commands.

    The command execution is essentially some transformation plus re-transmission of those via low-level interface (SPI). The protocol there is organised such that the executor will probably have to wait for response on SPI before it can continue processing other messages, that is why I need to queue the commands.

    I think that the usual solution using signals+slots mechanism is not suitable, since what I think I actually need is the Blocking queue - i.e. I need the second thread to block until I receive a command from the producer. At the same time, the executor has to block only for a certain amount of time and if there is no new commands in the queue for, e.g., 50 ms, it has to do some regular stuff.

    So, I think I need something like
    Producer:

    BlockingQueue.enqueue(command);
    

    Executor:

    if BlockingQueue.poll(50); // argument - timeout to wait
    { // There is a new message
        command = BlockingQueue.dequeue();
        // execute command, wait for response
    }
    else
    { // There were no commands for 50 ms
        // Do some regular stuff - e.g. send some regular request via SPI
    }
    

    There is some relevant topic for this question, and I think that it is possible to implement Blocking Queue as suggested here additionally using QSemaphore::tryAcquire(int n, int timeout).

    Is that the right approach in my case? Can the signals+slots mechanism be adapted to my use case?

    Thanks for advice in advance =)

    kshegunovK 1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Maybe http://doc.qt.io/qt-5/qtcore-threads-waitconditions-example.html will help you to give you the basic idea how to implement it :)

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      1 Reply Last reply
      2
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #3

        Hi,

        To add to @Christian-Ehrlicher, the QSemaphore example provides another possibility.

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        1
        • P podkiva

          Hello everyone,

          Suppose I have an application with two threads, first one (producer) produces some custom messages (a-ka commands with some additional data), while the second one (executor) is responsible for executing these commands.

          The command execution is essentially some transformation plus re-transmission of those via low-level interface (SPI). The protocol there is organised such that the executor will probably have to wait for response on SPI before it can continue processing other messages, that is why I need to queue the commands.

          I think that the usual solution using signals+slots mechanism is not suitable, since what I think I actually need is the Blocking queue - i.e. I need the second thread to block until I receive a command from the producer. At the same time, the executor has to block only for a certain amount of time and if there is no new commands in the queue for, e.g., 50 ms, it has to do some regular stuff.

          So, I think I need something like
          Producer:

          BlockingQueue.enqueue(command);
          

          Executor:

          if BlockingQueue.poll(50); // argument - timeout to wait
          { // There is a new message
              command = BlockingQueue.dequeue();
              // execute command, wait for response
          }
          else
          { // There were no commands for 50 ms
              // Do some regular stuff - e.g. send some regular request via SPI
          }
          

          There is some relevant topic for this question, and I think that it is possible to implement Blocking Queue as suggested here additionally using QSemaphore::tryAcquire(int n, int timeout).

          Is that the right approach in my case? Can the signals+slots mechanism be adapted to my use case?

          Thanks for advice in advance =)

          kshegunovK Offline
          kshegunovK Offline
          kshegunov
          Moderators
          wrote on last edited by kshegunov
          #4

          @podkiva said in Blocking Queue Between QThreads:

          There is some relevant topic for this question, and I think that it is possible to implement Blocking Queue as suggested here additionally using QSemaphore::tryAcquire(int n, int timeout).

          Yes, you can use that particular example with QSemaphore::tryAcquire.

          Is that the right approach in my case?

          No clue, this is something you should decide by yourself.

          Can the signals+slots mechanism be adapted to my use case?

          Sure. The usual worker object approach can work here as well. You add a slot in the worker of the consumer to handle the new commands and the implementation is trivially putting them in a queue. You also keep some kind of state (e.g. a boolean flag) if you're currently processing a command, if not you go on to process the pending ones, if not start a timer with the timeout to notify you if you don't receive any command an in the slot you execute whatever is the idle operation. Something along those lines:

          class Worker : public QObject
          {
              Q_OBJECT
          
          public:
              Worker(QObject * parent = nullptr)
                  : QObejct(parent), processing(false)
          
          public slots:
              void handleCommand(const Command & cmd)
              {
                  pending.enqueue(cmd);
                  QMetaObject::invokeMethod(this, &Worker::process);
              }
          
          protected:
               void process(const Command & cmd) // < doing the processing
               {
                    procesing = true;
                    // Do whatever it is you need ...
                    // ...
               }
          
          protected slots:
               void process()
               {
                   if (processing)
                       return; //< Do nothing, waiting for the current command to finish processing
          
                   if (!pending.empty())
                       process(pending.dequeue())
                   else
                       QTimer::singleShot(50, this, &Worker::doIdle)
               }
          
               void finishProcessing()
               {
                    processing = false;
                    QMetaObject::invokeMethod(this, &Worker::process);
               }
          
               void doIdle()
               {
                   if (processing)
                       return; //< We started some kind of task, don't do idle processing
          
                   // ...
                   QMetaObject::invokeMethod(this, &Worker::doIdle);
               }
          
          private:
              QQueue<Command> pending;
              bool processing;
          };
          

          Bear in mind I don't ordinarily test example code. You would use the above as usual for worker objects, but there some details you should work out depending on your exact task.

          Read and abide by the Qt Code of Conduct

          P 1 Reply Last reply
          1
          • kshegunovK kshegunov

            @podkiva said in Blocking Queue Between QThreads:

            There is some relevant topic for this question, and I think that it is possible to implement Blocking Queue as suggested here additionally using QSemaphore::tryAcquire(int n, int timeout).

            Yes, you can use that particular example with QSemaphore::tryAcquire.

            Is that the right approach in my case?

            No clue, this is something you should decide by yourself.

            Can the signals+slots mechanism be adapted to my use case?

            Sure. The usual worker object approach can work here as well. You add a slot in the worker of the consumer to handle the new commands and the implementation is trivially putting them in a queue. You also keep some kind of state (e.g. a boolean flag) if you're currently processing a command, if not you go on to process the pending ones, if not start a timer with the timeout to notify you if you don't receive any command an in the slot you execute whatever is the idle operation. Something along those lines:

            class Worker : public QObject
            {
                Q_OBJECT
            
            public:
                Worker(QObject * parent = nullptr)
                    : QObejct(parent), processing(false)
            
            public slots:
                void handleCommand(const Command & cmd)
                {
                    pending.enqueue(cmd);
                    QMetaObject::invokeMethod(this, &Worker::process);
                }
            
            protected:
                 void process(const Command & cmd) // < doing the processing
                 {
                      procesing = true;
                      // Do whatever it is you need ...
                      // ...
                 }
            
            protected slots:
                 void process()
                 {
                     if (processing)
                         return; //< Do nothing, waiting for the current command to finish processing
            
                     if (!pending.empty())
                         process(pending.dequeue())
                     else
                         QTimer::singleShot(50, this, &Worker::doIdle)
                 }
            
                 void finishProcessing()
                 {
                      processing = false;
                      QMetaObject::invokeMethod(this, &Worker::process);
                 }
            
                 void doIdle()
                 {
                     if (processing)
                         return; //< We started some kind of task, don't do idle processing
            
                     // ...
                     QMetaObject::invokeMethod(this, &Worker::doIdle);
                 }
            
            private:
                QQueue<Command> pending;
                bool processing;
            };
            

            Bear in mind I don't ordinarily test example code. You would use the above as usual for worker objects, but there some details you should work out depending on your exact task.

            P Offline
            P Offline
            podkiva
            wrote on last edited by
            #5

            @kshegunov Thank a lot for advices, it seems to me that the Semaphores solution is the most elegant in my case, since the signal+slots option still requires some extra workaround in my scenario.

            P.S. It seems you forgot to call finishProcessing() at the end of process(const Command & cmd) {...}.

            kshegunovK 1 Reply Last reply
            0
            • P podkiva

              @kshegunov Thank a lot for advices, it seems to me that the Semaphores solution is the most elegant in my case, since the signal+slots option still requires some extra workaround in my scenario.

              P.S. It seems you forgot to call finishProcessing() at the end of process(const Command & cmd) {...}.

              kshegunovK Offline
              kshegunovK Offline
              kshegunov
              Moderators
              wrote on last edited by
              #6

              @podkiva said in Blocking Queue Between QThreads:

              P.S. It seems you forgot to call finishProcessing() at the end of process(const Command & cmd) {...}.

              No, it's not an oversight. I left it for you to call whenever appropriate, as you might be doing some asynchronous operation in process(const Command & cmd), like reading a QProcess output, or reading a socket or w/e. In that case you'd connect the signal signifying the end of that async operation to the mentioned slot to push the next command to be handled.

              Read and abide by the Qt Code of Conduct

              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved