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. QQueue, is it thread safe

QQueue, is it thread safe

Scheduled Pinned Locked Moved Unsolved General and Desktop
15 Posts 7 Posters 8.5k Views 4 Watching
  • 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.
  • SPlattenS Offline
    SPlattenS Offline
    SPlatten
    wrote on last edited by SPlatten
    #1

    I want to use a QQueue to queue up messages for delivery over sockets. The question is, are the functions enqueue and dequeue thread safe or do I need to add mutex's around these calls?

    I have visited:

    https://doc.qt.io/qt-5/qqueue.html#details

    And I cannot see any mention of threads.

    Kind Regards,
    Sy

    J.HilkJ 1 Reply Last reply
    0
    • P Offline
      P Offline
      PaulNewman
      wrote on last edited by
      #2

      It's just a wrapper around QList so it's not safe, if you really wanna queue std::queue will be better solution

      SPlattenS aha_1980A 2 Replies Last reply
      1
      • SPlattenS SPlatten

        I want to use a QQueue to queue up messages for delivery over sockets. The question is, are the functions enqueue and dequeue thread safe or do I need to add mutex's around these calls?

        I have visited:

        https://doc.qt.io/qt-5/qqueue.html#details

        And I cannot see any mention of threads.

        J.HilkJ Offline
        J.HilkJ Offline
        J.Hilk
        Moderators
        wrote on last edited by
        #3

        @SPlatten

        92bc98fd-f9c1-4122-ac61-aae3fbfdb552-image.png

        only reentrant, like stated in the documentation


        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


        Q: What's that?
        A: It's blue light.
        Q: What does it do?
        A: It turns blue.

        1 Reply Last reply
        5
        • P PaulNewman

          It's just a wrapper around QList so it's not safe, if you really wanna queue std::queue will be better solution

          SPlattenS Offline
          SPlattenS Offline
          SPlatten
          wrote on last edited by
          #4

          @PaulNewman , what advantages does std::queue offer over QQueue ?

          Kind Regards,
          Sy

          P 1 Reply Last reply
          0
          • SPlattenS SPlatten

            @PaulNewman , what advantages does std::queue offer over QQueue ?

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

            @SPlatten look here https://doc.qt.io/qt-5/containers.html#algorithmic-complexity and here https://en.cppreference.com/w/cpp/container/deque

            QList<T>

            Random access - O(1)
            Insertion or removal of elements at the end or beginning - Amort. O(1)
            Insertion or removal of elements - O(n) 
            

            std::deque:

            Random access - O(1)
            Insertion or removal of elements at the end or beginning - O(1)
            Insertion or removal of elements - O(n) 
            

            Note:
            "Internally, QList<T> is represented as an array of T if sizeof(T) <= sizeof(void*) and T has been declared to be either a Q_MOVABLE_TYPE or a Q_PRIMITIVE_TYPE using Q_DECLARE_TYPEINFO. Otherwise, QList<T> is represented as an array of T* and the items are allocated on the heap."
            In most cases sizeof(T) > sizeof(void*) so queue(deque) will be faster.
            In Qt6 QList will be reworked and maybe perfomance will change

            kshegunovK 1 Reply Last reply
            0
            • P PaulNewman

              It's just a wrapper around QList so it's not safe, if you really wanna queue std::queue will be better solution

              aha_1980A Offline
              aha_1980A Offline
              aha_1980
              Lifetime Qt Champion
              wrote on last edited by
              #6

              @PaulNewman,

              you should state that std::queue is not thread safe either, because that was the question of @SPlatten.

              Regards

              Qt has to stay free or it will die.

              1 Reply Last reply
              3
              • A Offline
                A Offline
                Asperamanca
                wrote on last edited by
                #7

                If you share a reference to the same QQueue between threads, you need to implement proper locking.

                However, if you hand a copy of a QQueue to a thread, you are all done.

                See https://doc.qt.io/qt-5/threads-modules.html#threads-and-implicitly-shared-classes

                1 Reply Last reply
                1
                • M Offline
                  M Offline
                  mnesarco
                  wrote on last edited by
                  #8

                  It is not thread safe, you cannot enqueue and dequeue concurrently from different thread. I have used it and learned it by the hard way.

                  1 Reply Last reply
                  1
                  • P PaulNewman

                    @SPlatten look here https://doc.qt.io/qt-5/containers.html#algorithmic-complexity and here https://en.cppreference.com/w/cpp/container/deque

                    QList<T>

                    Random access - O(1)
                    Insertion or removal of elements at the end or beginning - Amort. O(1)
                    Insertion or removal of elements - O(n) 
                    

                    std::deque:

                    Random access - O(1)
                    Insertion or removal of elements at the end or beginning - O(1)
                    Insertion or removal of elements - O(n) 
                    

                    Note:
                    "Internally, QList<T> is represented as an array of T if sizeof(T) <= sizeof(void*) and T has been declared to be either a Q_MOVABLE_TYPE or a Q_PRIMITIVE_TYPE using Q_DECLARE_TYPEINFO. Otherwise, QList<T> is represented as an array of T* and the items are allocated on the heap."
                    In most cases sizeof(T) > sizeof(void*) so queue(deque) will be faster.
                    In Qt6 QList will be reworked and maybe perfomance will change

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

                    @PaulNewman said in QQueue, is it thread safe:

                    In most cases sizeof(T) > sizeof(void*) so queue(deque) will be faster.

                    Careful there. Algorithmic complexity is not the same as "faster", a linked list has the same complexity for appending as a regular vector, but the latter is almost certainly faster. The std::deque is a doubly linked list, and as such has reference stability, but also suffers from heap allocating each element and the pointer indirections that come with traversing it.

                    @SPlatten said in QQueue, is it thread safe:

                    And I cannot see any mention of threads.

                    Reentrant from @J-Hilk's screenshot is the cue.

                    I want to use a QQueue to queue up messages for delivery over sockets. The question is, are the functions enqueue and dequeue thread safe or do I need to add mutex's around these calls?

                    Use signals and slots and leverage the internal message queue in the QThread class' exec() implementation.

                    Read and abide by the Qt Code of Conduct

                    SPlattenS 1 Reply Last reply
                    3
                    • kshegunovK kshegunov

                      @PaulNewman said in QQueue, is it thread safe:

                      In most cases sizeof(T) > sizeof(void*) so queue(deque) will be faster.

                      Careful there. Algorithmic complexity is not the same as "faster", a linked list has the same complexity for appending as a regular vector, but the latter is almost certainly faster. The std::deque is a doubly linked list, and as such has reference stability, but also suffers from heap allocating each element and the pointer indirections that come with traversing it.

                      @SPlatten said in QQueue, is it thread safe:

                      And I cannot see any mention of threads.

                      Reentrant from @J-Hilk's screenshot is the cue.

                      I want to use a QQueue to queue up messages for delivery over sockets. The question is, are the functions enqueue and dequeue thread safe or do I need to add mutex's around these calls?

                      Use signals and slots and leverage the internal message queue in the QThread class' exec() implementation.

                      SPlattenS Offline
                      SPlattenS Offline
                      SPlatten
                      wrote on last edited by
                      #10

                      @kshegunov I am using signals and slots, but just because the member variable using QQueue variable is in a slot doesn't make it thread safe or does it?

                      I originally asked because I am using signals and slots, but do I need to add a mutex in the slot and thread body to protect the QQueue member?

                      Kind Regards,
                      Sy

                      kshegunovK 1 Reply Last reply
                      0
                      • SPlattenS SPlatten

                        @kshegunov I am using signals and slots, but just because the member variable using QQueue variable is in a slot doesn't make it thread safe or does it?

                        I originally asked because I am using signals and slots, but do I need to add a mutex in the slot and thread body to protect the QQueue member?

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

                        @SPlatten said in QQueue, is it thread safe:

                        @kshegunov I am using signals and slots, but just because the member variable using QQueue variable is in a slot doesn't make it thread safe or does it?
                        I originally asked because I am using signals and slots, but do I need to add a mutex in the slot and thread body to protect the QQueue member?

                        I can't say. Depends on few things:

                        1. Are you using the default implementation of QThread::run and thus have you an event loop running there?
                        2. Are you connecting the signals/slots with Qt::AutoConnection or are you forcing the connection type? Provide a small snippet out of the slot, please, so we know what we are talking about.

                        *) A member/variable can't be thread-safe, this is a jargon we use. It means that (all) its class' methods are either reentrant/thread-safe/nonreentrant/non-thread safe. There can be mixes of these for different functions/methods, though.
                        Data itself is oblivious to threads, the concurrent access is significant for the execution paths (i.e. function calls), so a function/method can be assigned that meaning, not the object itself.

                        Read and abide by the Qt Code of Conduct

                        1 Reply Last reply
                        1
                        • SPlattenS Offline
                          SPlattenS Offline
                          SPlatten
                          wrote on last edited by
                          #12

                          @kshegunov , my connections are typically:

                          QObject::connect(this, &clsMsgSender::sendJSON
                                          ,this, &clsMsgSender::onSendJSON);
                          

                          Here is an example of that slot:

                          void clsMsgSender::onSendJSON(const QJsonObject &crobjJSON) {
                              clsMsgSender* pService = clsMsgSender::pGetService();
                          
                              if ( pService == nullptr ) {
                              //Shouldn't get here!
                                  return;
                              }
                              if ( pService->isRunning() != true ) {
                              //Start service
                                  emit pService->startService();
                              }
                              QMutexLocker lock(&pService->mMutex);
                              pService->mqueMsgsOut.enqueue(crobjJSON);
                          }
                          

                          'pService' points to the static instance of the same class which has the QQueue member.

                          Kind Regards,
                          Sy

                          kshegunovK 1 Reply Last reply
                          0
                          • SPlattenS SPlatten

                            @kshegunov , my connections are typically:

                            QObject::connect(this, &clsMsgSender::sendJSON
                                            ,this, &clsMsgSender::onSendJSON);
                            

                            Here is an example of that slot:

                            void clsMsgSender::onSendJSON(const QJsonObject &crobjJSON) {
                                clsMsgSender* pService = clsMsgSender::pGetService();
                            
                                if ( pService == nullptr ) {
                                //Shouldn't get here!
                                    return;
                                }
                                if ( pService->isRunning() != true ) {
                                //Start service
                                    emit pService->startService();
                                }
                                QMutexLocker lock(&pService->mMutex);
                                pService->mqueMsgsOut.enqueue(crobjJSON);
                            }
                            

                            'pService' points to the static instance of the same class which has the QQueue member.

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

                            Since you're using a global instance that's touched in multiple places (i.e. threads) you need to protect each and every access. What you should follow up with is the thread safety classics: the consumer-producer problem (there's also an example implementation in Qt's docs).

                            pService->isRunning() is a race condition unless you took special measures (e.g. using an atomic to set/get the status).

                            QMutexLocker lock(&pService->mMutex);
                            Should be inside the pService instance and should be locked unlocked by the class API, ordinarily. You're spilling the class implementation here, which with strong coupling (between classes) is going to bite you sooner or later.

                            Additionally, please show the clsMsgSender::pGetService too. I suspect you have a problem there as well.

                            Read and abide by the Qt Code of Conduct

                            SPlattenS 1 Reply Last reply
                            1
                            • kshegunovK kshegunov

                              Since you're using a global instance that's touched in multiple places (i.e. threads) you need to protect each and every access. What you should follow up with is the thread safety classics: the consumer-producer problem (there's also an example implementation in Qt's docs).

                              pService->isRunning() is a race condition unless you took special measures (e.g. using an atomic to set/get the status).

                              QMutexLocker lock(&pService->mMutex);
                              Should be inside the pService instance and should be locked unlocked by the class API, ordinarily. You're spilling the class implementation here, which with strong coupling (between classes) is going to bite you sooner or later.

                              Additionally, please show the clsMsgSender::pGetService too. I suspect you have a problem there as well.

                              SPlattenS Offline
                              SPlattenS Offline
                              SPlatten
                              wrote on last edited by SPlatten
                              #14

                              @kshegunov

                              private:
                                  static clsMsgSender* mspService;
                              
                              public:
                                  static clsMsgSender* pGetService() { return clsMsgSender::mspService; }
                              

                              Kind Regards,
                              Sy

                              kshegunovK 1 Reply Last reply
                              0
                              • SPlattenS SPlatten

                                @kshegunov

                                private:
                                    static clsMsgSender* mspService;
                                
                                public:
                                    static clsMsgSender* pGetService() { return clsMsgSender::mspService; }
                                
                                kshegunovK Offline
                                kshegunovK Offline
                                kshegunov
                                Moderators
                                wrote on last edited by
                                #15

                                Yes, this is fine as long as you guarantee that the construction and destruction are not concurrent between different threads.

                                Read and abide by the Qt Code of Conduct

                                1 Reply Last reply
                                1

                                • Login

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