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. Non-Reentrant Class Use In Multithreaded Program
Forum Updated to NodeBB v4.3 + New Features

Non-Reentrant Class Use In Multithreaded Program

Scheduled Pinned Locked Moved Solved General and Desktop
64 Posts 6 Posters 20.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.
  • JonBJ JonB

    @kshegunov
    I have two questions about using the QMutex pattern to synchronise reads with writes, please:

    1. I assume that if the reader wants to read just one item it must still lock the whole object and the writer must lock the whole object, as the reader/iterator could be thrown by the write creating/deleting an item in the middle of the data?

    2. Given the above, what pattern would we use to allow multiple-simultaneous-readers exclusive from single-writer? A reader would still need to grab the QMutex to prevent a writer, but we don't want to stop a second reader which would also want the QMutex?

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

    These are relatively hard questions to answer, because it will depend on the way the data's organized. I'd make an effort to elaborate the best I can, nonetheless.

    For 1:

    Race conditions are an inevitable consequence of memory access, so if a race condition occurs depends heavily on the memory layout of the object/memory block in question. Say we are talking about a regular reentrant object, then it is safe in theory to call two methods simultaneously (i.e. from different threads) provided the mentioned two methods work on a different data member of that class. For example, if you have the very simple:

    struct MyStruct
    {
        int a, b;
    };
    

    Then you can completely safely read or modify a from one thread and b from from another as long as you don't touch the other member. The same considerations apply to plain C arrays of data, e.g.:

    int * myarray = new int[200];
    

    Then you can read or modify simultaneously from different threads different parts of the array; meaning you can write to the first element while reading the second from different threads safely. If you can guarantee there's no overlap between the memory accesses made from the different threads, then there's no race condition, and you're completely fine. This is exploited, for example, if you have the consumer-producer problem and there's an example in Qt's documentation of how it can be achieved with semaphores. To make your regular objects work like this, however, is often too finicky and error prone, so you'd usually opt for a serial access (i.e. through a mutex). Also see answer to question #2 for related information.

    Now, if you use a container (for example std::vector or especially QVector due to implicit sharing) it's a bit more complicated. If you're working with std::vector you're fine obtaining a read or write iterator directly, because there's no data sharing behind the scenes. Then the only problem to solve is like with regular arrays - to ensure there are no concurrent memory accesses of the different elements. If you use QVector (or a QList, QHash, etc.) on the other hand then obtaining the write iterator is by itself a write operation, because the data may be shared and data copy might occur at that point. After the possible detach has happened then the same considerations as for std::vector apply.

    For 2:
    If you want to permit multiple readers and writers to access a specific data block, then a more elaborate scheme for locking is needed. As you correctly observed mutexes are exclusive, hence the name - mutual exclusive lock. They also guard a single resource, for example the whole array. If you need to have a threading primitive that provides guarding of multiple resources, then you need a semaphore (like in the consumer-producer example sourced above). On the other hand if you're satisfied with exclusive access only for write-induced races, which is exactly your question - allowing a single write at one time, but simultaneous reads, you could use Qt's QReadWriteLock which provides a locking scheme for that specific case (internal implementation isn't that important here, so I'll not venture into it).

    Here I also would like to note that if you can prepopulate the data, then it could be a very viable approach to avoid needless locking. Because after you have the data in a container (provided it holds reentrant objects and the classes respect the method's const modifier, meaning no const_cast or mutable), you could use const-only access to that container and data in as many threads as you need. I quite often do that in my work with hashes.

    Read and abide by the Qt Code of Conduct

    JonBJ VRoninV 2 Replies Last reply
    3
    • kshegunovK kshegunov

      These are relatively hard questions to answer, because it will depend on the way the data's organized. I'd make an effort to elaborate the best I can, nonetheless.

      For 1:

      Race conditions are an inevitable consequence of memory access, so if a race condition occurs depends heavily on the memory layout of the object/memory block in question. Say we are talking about a regular reentrant object, then it is safe in theory to call two methods simultaneously (i.e. from different threads) provided the mentioned two methods work on a different data member of that class. For example, if you have the very simple:

      struct MyStruct
      {
          int a, b;
      };
      

      Then you can completely safely read or modify a from one thread and b from from another as long as you don't touch the other member. The same considerations apply to plain C arrays of data, e.g.:

      int * myarray = new int[200];
      

      Then you can read or modify simultaneously from different threads different parts of the array; meaning you can write to the first element while reading the second from different threads safely. If you can guarantee there's no overlap between the memory accesses made from the different threads, then there's no race condition, and you're completely fine. This is exploited, for example, if you have the consumer-producer problem and there's an example in Qt's documentation of how it can be achieved with semaphores. To make your regular objects work like this, however, is often too finicky and error prone, so you'd usually opt for a serial access (i.e. through a mutex). Also see answer to question #2 for related information.

      Now, if you use a container (for example std::vector or especially QVector due to implicit sharing) it's a bit more complicated. If you're working with std::vector you're fine obtaining a read or write iterator directly, because there's no data sharing behind the scenes. Then the only problem to solve is like with regular arrays - to ensure there are no concurrent memory accesses of the different elements. If you use QVector (or a QList, QHash, etc.) on the other hand then obtaining the write iterator is by itself a write operation, because the data may be shared and data copy might occur at that point. After the possible detach has happened then the same considerations as for std::vector apply.

      For 2:
      If you want to permit multiple readers and writers to access a specific data block, then a more elaborate scheme for locking is needed. As you correctly observed mutexes are exclusive, hence the name - mutual exclusive lock. They also guard a single resource, for example the whole array. If you need to have a threading primitive that provides guarding of multiple resources, then you need a semaphore (like in the consumer-producer example sourced above). On the other hand if you're satisfied with exclusive access only for write-induced races, which is exactly your question - allowing a single write at one time, but simultaneous reads, you could use Qt's QReadWriteLock which provides a locking scheme for that specific case (internal implementation isn't that important here, so I'll not venture into it).

      Here I also would like to note that if you can prepopulate the data, then it could be a very viable approach to avoid needless locking. Because after you have the data in a container (provided it holds reentrant objects and the classes respect the method's const modifier, meaning no const_cast or mutable), you could use const-only access to that container and data in as many threads as you need. I quite often do that in my work with hashes.

      JonBJ Online
      JonBJ Online
      JonB
      wrote on last edited by
      #17

      @kshegunov
      First, thanks for your comprehensive explanation.

      For #1, you're making it way more complex than I had in mind. Say I have one thread writer & one thread reader, and my data is, say, a list/array of integers (forget vectors), no structures or whatever. I wish to use QMutex. All I wanted to verify is: (a) writer can insert/delete/update list/array; (b) reader wants just to read element #10; (c) confirm that the implementation must be QMutex for whole object/list/array, so that writer cannot change elements while reader trying to read one element.

      For #2, QReadWriteLock is just the ticket instead of QMutex, thank you.

      kshegunovK 1 Reply Last reply
      0
      • JonBJ JonB

        @kshegunov
        First, thanks for your comprehensive explanation.

        For #1, you're making it way more complex than I had in mind. Say I have one thread writer & one thread reader, and my data is, say, a list/array of integers (forget vectors), no structures or whatever. I wish to use QMutex. All I wanted to verify is: (a) writer can insert/delete/update list/array; (b) reader wants just to read element #10; (c) confirm that the implementation must be QMutex for whole object/list/array, so that writer cannot change elements while reader trying to read one element.

        For #2, QReadWriteLock is just the ticket instead of QMutex, thank you.

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

        @JNBarchan said in Non-Reentrant Class Use In Multithreaded Program:

        confirm that the implementation must be QMutex for whole object/list/array, so that writer cannot change elements while reader trying to read one element.

        Yes, I confirm. While the mutex is locked the whole object/list/array is owned by the locking thread. All other threads requesting access are waiting and one of them (in an unspecified order) will acquire the mutex when the owning thread unlocks it.

        Read and abide by the Qt Code of Conduct

        1 Reply Last reply
        2
        • kshegunovK kshegunov

          These are relatively hard questions to answer, because it will depend on the way the data's organized. I'd make an effort to elaborate the best I can, nonetheless.

          For 1:

          Race conditions are an inevitable consequence of memory access, so if a race condition occurs depends heavily on the memory layout of the object/memory block in question. Say we are talking about a regular reentrant object, then it is safe in theory to call two methods simultaneously (i.e. from different threads) provided the mentioned two methods work on a different data member of that class. For example, if you have the very simple:

          struct MyStruct
          {
              int a, b;
          };
          

          Then you can completely safely read or modify a from one thread and b from from another as long as you don't touch the other member. The same considerations apply to plain C arrays of data, e.g.:

          int * myarray = new int[200];
          

          Then you can read or modify simultaneously from different threads different parts of the array; meaning you can write to the first element while reading the second from different threads safely. If you can guarantee there's no overlap between the memory accesses made from the different threads, then there's no race condition, and you're completely fine. This is exploited, for example, if you have the consumer-producer problem and there's an example in Qt's documentation of how it can be achieved with semaphores. To make your regular objects work like this, however, is often too finicky and error prone, so you'd usually opt for a serial access (i.e. through a mutex). Also see answer to question #2 for related information.

          Now, if you use a container (for example std::vector or especially QVector due to implicit sharing) it's a bit more complicated. If you're working with std::vector you're fine obtaining a read or write iterator directly, because there's no data sharing behind the scenes. Then the only problem to solve is like with regular arrays - to ensure there are no concurrent memory accesses of the different elements. If you use QVector (or a QList, QHash, etc.) on the other hand then obtaining the write iterator is by itself a write operation, because the data may be shared and data copy might occur at that point. After the possible detach has happened then the same considerations as for std::vector apply.

          For 2:
          If you want to permit multiple readers and writers to access a specific data block, then a more elaborate scheme for locking is needed. As you correctly observed mutexes are exclusive, hence the name - mutual exclusive lock. They also guard a single resource, for example the whole array. If you need to have a threading primitive that provides guarding of multiple resources, then you need a semaphore (like in the consumer-producer example sourced above). On the other hand if you're satisfied with exclusive access only for write-induced races, which is exactly your question - allowing a single write at one time, but simultaneous reads, you could use Qt's QReadWriteLock which provides a locking scheme for that specific case (internal implementation isn't that important here, so I'll not venture into it).

          Here I also would like to note that if you can prepopulate the data, then it could be a very viable approach to avoid needless locking. Because after you have the data in a container (provided it holds reentrant objects and the classes respect the method's const modifier, meaning no const_cast or mutable), you could use const-only access to that container and data in as many threads as you need. I quite often do that in my work with hashes.

          VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by VRonin
          #19

          @kshegunov said in Non-Reentrant Class Use In Multithreaded Program:

          and the classes respect the method's const modifier, meaning no const_cast or mutable

          Just a small note, the above is not exhaustive. For example:

          class BreakingConst{
          int* a;
          BreakingConst(int b=0) : a(new int(b)){}
          ~BreakingConst(){delete a;}
          int getIncreasingA() const{ return (*a)++;}
          };
          

          has no const_cast or mutable but still breaks if used as described

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          kshegunovK 1 Reply Last reply
          2
          • VRoninV VRonin

            @kshegunov said in Non-Reentrant Class Use In Multithreaded Program:

            and the classes respect the method's const modifier, meaning no const_cast or mutable

            Just a small note, the above is not exhaustive. For example:

            class BreakingConst{
            int* a;
            BreakingConst(int b=0) : a(new int(b)){}
            ~BreakingConst(){delete a;}
            int getIncreasingA() const{ return (*a)++;}
            };
            

            has no const_cast or mutable but still breaks if used as described

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

            It's probably somewhat of a fringe use case, but yes, you are right. The const modifier doesn't implicitly propagate to the indirectly referenced data. a is of type int * const in that case, which allows you to actually dereference the pointer and modify the underlying data. The same behavior is true for a heap-allocated array too, however with auto-storage:

            class BreakingConst
            {
                int a[1];
            
                BreakingConst(int b=0) { a[0] = b; }
                ~BreakingConst()  { delete a; }
                int getIncreasingA() const  { return a[0]++; }
            };
            

            The compiler knows what's going on and will prevent it.

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            1
            • C Offline
              C Offline
              Crag_Hack
              wrote on last edited by
              #21

              Last question for this thread - if you go here to the first answer Kuba is complaining about iterators. Any merit to this claim? Anything to worry about? When he says internal pointers that doesn' t mean a pointer to a qt class does it? Only an iterator pointer right?
              He says:

              Sidebar: If you use iterators or internal pointers to data on non-const instances, you must forcibly detach() the object before constructing the iterators/pointers. The problem with iterators is that they become invalidated when an object's data is detached, and detaching can happen in any thread where the instance is non-const - so at least one thread will end up with invalid iterators. I won't talk any more of this, the takeaway is that implicitly shared data types are tricky to implement and use safely. With C++11, there's no need for implicit sharing anymore: they were a workaround for the lack of move semantics in C++98.
              
              kshegunovK 1 Reply Last reply
              0
              • C Crag_Hack

                Last question for this thread - if you go here to the first answer Kuba is complaining about iterators. Any merit to this claim? Anything to worry about? When he says internal pointers that doesn' t mean a pointer to a qt class does it? Only an iterator pointer right?
                He says:

                Sidebar: If you use iterators or internal pointers to data on non-const instances, you must forcibly detach() the object before constructing the iterators/pointers. The problem with iterators is that they become invalidated when an object's data is detached, and detaching can happen in any thread where the instance is non-const - so at least one thread will end up with invalid iterators. I won't talk any more of this, the takeaway is that implicitly shared data types are tricky to implement and use safely. With C++11, there's no need for implicit sharing anymore: they were a workaround for the lack of move semantics in C++98.
                
                kshegunovK Offline
                kshegunovK Offline
                kshegunov
                Moderators
                wrote on last edited by
                #22

                @Crag_Hack said in Non-Reentrant Class Use In Multithreaded Program:

                Any merit to this claim?

                Yes, some. See this thread on the mailing list.

                Anything to worry about?

                Don't call write operations, including non-const iterator retrieval, on an object from different threads!

                When he says internal pointers that doesn' t mean a pointer to a qt class does it?

                No, he means pointers to data that are kept internally by Qt. You don't have access to them, but you need to take into a account they exist. That's also the reason why in the docs it's said to not keep iterators to a container that may get modified (i.e. the container getting out of scope).

                Only an iterator pointer right?

                The iterator is a pointer to the data or an object keeping a pointer to the data. So in a sense you can say the iterator is a pointer (and it is for contiguous data classes like QVector).

                With C++11, there's no need for implicit sharing anymore: they were a workaround for the lack of move semantics in C++98.

                This is incorrect though. Qt's signal-slot mechanism could not work effectively without implicit sharing. Move semantics is not a panacea, and certainly solves no problems when an object has to be queued through Qt's event loop.

                Read and abide by the Qt Code of Conduct

                1 Reply Last reply
                2
                • C Offline
                  C Offline
                  Crag_Hack
                  wrote on last edited by
                  #23

                  Thanks kshegunov... so nothing to worry about unless you use iterators right?

                  kshegunovK 1 Reply Last reply
                  0
                  • C Crag_Hack

                    Thanks kshegunov... so nothing to worry about unless you use iterators right?

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

                    @kshegunov said in Non-Reentrant Class Use In Multithreaded Program:

                    Anything to worry about?

                    Don't call write operations, including non-const iterator retrieval, on an object from different threads!

                    Read and abide by the Qt Code of Conduct

                    1 Reply Last reply
                    1
                    • C Offline
                      C Offline
                      Crag_Hack
                      wrote on last edited by Crag_Hack
                      #25

                      I have two quick followup questions:

                      1. There's no possibility of two different non-reentrant classes sharing the same global (program-wise) resources, e. g. static variables? So say QStorageInfo uses the same globals/statics as QPair, you use QStorageInfo in one thread then QPair in another - they're not gonna fight each other and end up with a race condition and everything is safe right? (arbitrary choice of classes)
                      2. I'm not confident enough in my understanding of multithreading to feel comfortable with my code right now - so I'll just state it explicity. I am calling job.sortFileList(); in my worker thread. The job object is a custom class for backup jobs. I send it to the worker thread using signals and slots. The sortFileList() function follows as well as the comparison function. fileList is QList<std::pair<QString, QString> > fileList;
                      void BackupJob::sortFileList()
                      {
                          qSort(fileList.begin(), fileList.end(), fileListCompare);
                      }
                      bool fileListCompare(const std::pair<QString, QString> &leftFileStringPair, const std::pair<QString, QString> &rightFileStringPair)
                      {...}
                      

                      fileListCompare() is a function declared in the BackupJob.h file but not a member of the BackupJob class (global right?). Is this call to qSort safe? I'm guessing yes since the worker thread uses its own instance of the class (the class contains no non-reentrant objects, functions, or anything) and the iterators are constant (they're constant right?).
                      *edit - when I hover above the iterators in Qt Creator they appear as const_iterators not sure why though I didn't declare fileList as const
                      Thanks for the help!

                      kshegunovK 1 Reply Last reply
                      0
                      • C Crag_Hack

                        I have two quick followup questions:

                        1. There's no possibility of two different non-reentrant classes sharing the same global (program-wise) resources, e. g. static variables? So say QStorageInfo uses the same globals/statics as QPair, you use QStorageInfo in one thread then QPair in another - they're not gonna fight each other and end up with a race condition and everything is safe right? (arbitrary choice of classes)
                        2. I'm not confident enough in my understanding of multithreading to feel comfortable with my code right now - so I'll just state it explicity. I am calling job.sortFileList(); in my worker thread. The job object is a custom class for backup jobs. I send it to the worker thread using signals and slots. The sortFileList() function follows as well as the comparison function. fileList is QList<std::pair<QString, QString> > fileList;
                        void BackupJob::sortFileList()
                        {
                            qSort(fileList.begin(), fileList.end(), fileListCompare);
                        }
                        bool fileListCompare(const std::pair<QString, QString> &leftFileStringPair, const std::pair<QString, QString> &rightFileStringPair)
                        {...}
                        

                        fileListCompare() is a function declared in the BackupJob.h file but not a member of the BackupJob class (global right?). Is this call to qSort safe? I'm guessing yes since the worker thread uses its own instance of the class (the class contains no non-reentrant objects, functions, or anything) and the iterators are constant (they're constant right?).
                        *edit - when I hover above the iterators in Qt Creator they appear as const_iterators not sure why though I didn't declare fileList as const
                        Thanks for the help!

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

                        @Crag_Hack said in Non-Reentrant Class Use In Multithreaded Program:

                        There's no possibility of two different non-reentrant classes sharing the same global (program-wise) resources, e. g. static variables? So say QStorageInfo uses the same globals/statics as QPair, you use QStorageInfo in one thread then QPair in another - they're not gonna fight each other and end up with a race condition and everything is safe right? (arbitrary choice of classes)

                        Actually this is exactly what makes the classes non-reentrant - having a shared global/static variable. Objects of those classes are safe to use from different threads only if they're explicitly thread-safe, e.g. QSemaphore/QMutex in contrast to QWidget, which is neither reentrant nor thread-safe.

                        Is this call to qSort safe?

                        As long as 2 conditions are met:

                        1. the fileListCompare doesn't use global data (i.e. static/global variables) - it's reentrant - or if it does, then all accesses to the globals is serialized between different threads (with a mutex) - it's thread-safe.
                        2. fileList isn't modified while qSort is executed. This would be true if BackupJob is reentrant, or more specifically - the thread operates on it's own instance of the fileList data member.

                        when I hover above the iterators in Qt Creator they appear as const_iterators not sure why though I didn't declare fileList as const

                        It's a deficiency of the IDE you use. qSort requires non-const iterators. As a side note, you should use std::sort instead of the legacy qSort.

                        Read and abide by the Qt Code of Conduct

                        1 Reply Last reply
                        2
                        • C Offline
                          C Offline
                          Crag_Hack
                          wrote on last edited by
                          #27

                          Thanks kshegunov! :)

                          Actually this is exactly what makes the classes non-reentrant - having a shared global/static variable.
                          I understand that but I wonder whether two different classes ever share the same global/static variable. Then you might be in trouble if you used one in one thread and the other in another thread, even though each object is isolated to its own thread there still is an issue since they share those globals/statics.

                          1. the fileListCompare doesn't use global data (i.e. static/global variables) - it's reentrant - or if it does, then all accesses to the globals is serialized between different threads (with a mutex) - it's thread-safe.
                          It only uses the referance parameters passed to the function.

                          2. fileList isn't modified while qSort is executed. This would be true if BackupJob is reentrant, or more specifically - the thread operates on it's own instance of the fileList data member.
                          The thread operates on its own instance of a list of backupjob objects or an individual backupjob object which is passed to the thread through signals/slots. fileList is a member variable of the backupJob objects and the backupJob objects only use reentrant variables/objects. So safe right?

                          As a side note, you should use std::sort instead of the legacy qSort.
                          I wasn't even aware qSort had been obsoleted. The first google result says nothing of such matters since it's Qt 4.8. For std::sort we just pass it the same QList::begin() QList::constBegin() QList::end() QList::constEnd() right?

                          And how do I make those neat bars on the left for styling replied to comments?

                          JKSHJ 1 Reply Last reply
                          0
                          • C Crag_Hack

                            Thanks kshegunov! :)

                            Actually this is exactly what makes the classes non-reentrant - having a shared global/static variable.
                            I understand that but I wonder whether two different classes ever share the same global/static variable. Then you might be in trouble if you used one in one thread and the other in another thread, even though each object is isolated to its own thread there still is an issue since they share those globals/statics.

                            1. the fileListCompare doesn't use global data (i.e. static/global variables) - it's reentrant - or if it does, then all accesses to the globals is serialized between different threads (with a mutex) - it's thread-safe.
                            It only uses the referance parameters passed to the function.

                            2. fileList isn't modified while qSort is executed. This would be true if BackupJob is reentrant, or more specifically - the thread operates on it's own instance of the fileList data member.
                            The thread operates on its own instance of a list of backupjob objects or an individual backupjob object which is passed to the thread through signals/slots. fileList is a member variable of the backupJob objects and the backupJob objects only use reentrant variables/objects. So safe right?

                            As a side note, you should use std::sort instead of the legacy qSort.
                            I wasn't even aware qSort had been obsoleted. The first google result says nothing of such matters since it's Qt 4.8. For std::sort we just pass it the same QList::begin() QList::constBegin() QList::end() QList::constEnd() right?

                            And how do I make those neat bars on the left for styling replied to comments?

                            JKSHJ Offline
                            JKSHJ Offline
                            JKSH
                            Moderators
                            wrote on last edited by
                            #28

                            @Crag_Hack said in Non-Reentrant Class Use In Multithreaded Program:

                            Actually this is exactly what makes the classes non-reentrant - having a shared global/static variable.
                            I understand that but I wonder whether two different classes ever share the same global/static variable. Then you might be in trouble if you used one in one thread and the other in another thread, even though each object is isolated to its own thread there still is an issue since they share those globals/statics.

                            Yes, this does happen.

                            Such classes must be used from the GUI thread only (e.g. QWidget, QPixmap must only be used in the same thread that created a QApplication)

                            2. fileList isn't modified while qSort is executed. This would be true if BackupJob is reentrant, or more specifically - the thread operates on it's own instance of the fileList data member.
                            The thread operates on its own instance of a list of backupjob objects or an individual backupjob object which is passed to the thread through signals/slots. fileList is a member variable of the backupJob objects and the backupJob objects only use reentrant variables/objects. So safe right?

                            Sounds good.

                            As a side note, you should use std::sort instead of the legacy qSort.
                            I wasn't even aware qSort had been obsoleted. The first google result says nothing of such matters since it's Qt 4.8.

                            See http://doc.qt.io/qt-5/qtalgorithms-obsolete.html

                            Qt 4.8 is obsolete too. Support ended in December 2015.

                            For std::sort we just pass it the same QList::begin() QList::constBegin() QList::end() QList::constEnd() right?

                            Yes.

                            And how do I make those neat bars on the left for styling replied to comments?

                            Click the "reply"/"quote" link at the bottom-right of each post.

                            Paragraphs that start with > are treated as quotes.

                            Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                            C 1 Reply Last reply
                            2
                            • JKSHJ JKSH

                              @Crag_Hack said in Non-Reentrant Class Use In Multithreaded Program:

                              Actually this is exactly what makes the classes non-reentrant - having a shared global/static variable.
                              I understand that but I wonder whether two different classes ever share the same global/static variable. Then you might be in trouble if you used one in one thread and the other in another thread, even though each object is isolated to its own thread there still is an issue since they share those globals/statics.

                              Yes, this does happen.

                              Such classes must be used from the GUI thread only (e.g. QWidget, QPixmap must only be used in the same thread that created a QApplication)

                              2. fileList isn't modified while qSort is executed. This would be true if BackupJob is reentrant, or more specifically - the thread operates on it's own instance of the fileList data member.
                              The thread operates on its own instance of a list of backupjob objects or an individual backupjob object which is passed to the thread through signals/slots. fileList is a member variable of the backupJob objects and the backupJob objects only use reentrant variables/objects. So safe right?

                              Sounds good.

                              As a side note, you should use std::sort instead of the legacy qSort.
                              I wasn't even aware qSort had been obsoleted. The first google result says nothing of such matters since it's Qt 4.8.

                              See http://doc.qt.io/qt-5/qtalgorithms-obsolete.html

                              Qt 4.8 is obsolete too. Support ended in December 2015.

                              For std::sort we just pass it the same QList::begin() QList::constBegin() QList::end() QList::constEnd() right?

                              Yes.

                              And how do I make those neat bars on the left for styling replied to comments?

                              Click the "reply"/"quote" link at the bottom-right of each post.

                              Paragraphs that start with > are treated as quotes.

                              C Offline
                              C Offline
                              Crag_Hack
                              wrote on last edited by Crag_Hack
                              #29

                              Thanks JKSH

                              Yes, this does happen.

                              Such classes must be used from the GUI thread only (e.g. QWidget, QPixmap must only be used in the same thread that created a QApplication)

                              I forgot to clarify in the previous post not just two objects isolated to their own threads but two objects of two different classes... But you knew that right? Anything else to know? Are these classes the exception, perhaps only graphical classes?

                              1. the fileListCompare doesn't use global data (i.e. static/global variables) - it's reentrant - or if it does, then all accesses to the globals is serialized between different threads (with a mutex) - it's thread-safe.

                              It only uses the referance parameters passed to the function.

                              And of course this sounds good as well right...

                              JKSHJ 1 Reply Last reply
                              0
                              • C Crag_Hack

                                Thanks JKSH

                                Yes, this does happen.

                                Such classes must be used from the GUI thread only (e.g. QWidget, QPixmap must only be used in the same thread that created a QApplication)

                                I forgot to clarify in the previous post not just two objects isolated to their own threads but two objects of two different classes... But you knew that right? Anything else to know? Are these classes the exception, perhaps only graphical classes?

                                1. the fileListCompare doesn't use global data (i.e. static/global variables) - it's reentrant - or if it does, then all accesses to the globals is serialized between different threads (with a mutex) - it's thread-safe.

                                It only uses the referance parameters passed to the function.

                                And of course this sounds good as well right...

                                JKSHJ Offline
                                JKSHJ Offline
                                JKSH
                                Moderators
                                wrote on last edited by
                                #30

                                @Crag_Hack said in Non-Reentrant Class Use In Multithreaded Program:

                                I forgot to clarify in the previous post not just two objects isolated to their own threads but two objects of two different classes... But you knew that right?

                                Yes, I knew that :)

                                The widget example still stands: Suppose you create a very simple program that consists of only 1 QApplication object and 1 QWidget object. These two objects are not allowed to be in different threads.

                                Anything else to know? Are these classes the exception, perhaps only graphical classes?

                                None that I can think of. I'm quite sure it's only the graphical classes with QApplication/QGuiApplication.

                                1. the fileListCompare doesn't use global data (i.e. static/global variables) - it's reentrant - or if it does, then all accesses to the globals is serialized between different threads (with a mutex) - it's thread-safe.

                                It only uses the referance parameters passed to the function.

                                And of course this sounds good as well right...

                                You said: fileListCompare() only uses references parameters. I presume you were confirming that fileListCompare() doesn't use global/static variables.

                                As @kshegunov said: If fileListCompare() doesn't use global/static variables, then fileListCompare() is a reentrant function.

                                Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                                1 Reply Last reply
                                2
                                • C Offline
                                  C Offline
                                  Crag_Hack
                                  wrote on last edited by
                                  #31

                                  A couple more questions creeped into my domain... thankfully they're quick :) is qDebug() reentrant or should it not be used from multiple threads? All STL classes are reentrant right except for <atomic> and std::atomic guys right?

                                  JKSHJ 1 Reply Last reply
                                  0
                                  • C Crag_Hack

                                    A couple more questions creeped into my domain... thankfully they're quick :) is qDebug() reentrant or should it not be used from multiple threads? All STL classes are reentrant right except for <atomic> and std::atomic guys right?

                                    JKSHJ Offline
                                    JKSHJ Offline
                                    JKSH
                                    Moderators
                                    wrote on last edited by JKSH
                                    #32

                                    @Crag_Hack said in Non-Reentrant Class Use In Multithreaded Program:

                                    A couple more questions creeped into my domain... thankfully they're quick :) is qDebug() reentrant or should it not be used from multiple threads?

                                    qDebug() itself is thread-safe. It can be called simultaneously from multiple threads, without endangering your application.

                                    However, qDebug() sends data to stderr by default, which is unbuffered. That means: If you send a long stream of "A"s from one thread and a long stream of "B"s from another thread, you might see interleaved text when viewing stderr:

                                    "AAAAAAAAAABBBBBBBBBBAAAAAAAAAABBBBBBBBBB"

                                    To avoid this, call qInstallMessageHandler() to send qDebug() output to a buffered stream (like stdout or a file).

                                    All STL classes are reentrant right except for <atomic> and std::atomic guys right?

                                    I'd say so

                                    Qt Doc Search for browsers: forum.qt.io/topic/35616/web-browser-extension-for-improved-doc-searches

                                    1 Reply Last reply
                                    2
                                    • C Offline
                                      C Offline
                                      Crag_Hack
                                      wrote on last edited by Crag_Hack
                                      #33

                                      Another related question I conjured up - how come some Qt classes aren't reeentrant that would be quite more useful if they were? I.E. QPair, QStorageInfo. My program makes use of drive storage info in both the main GUI thread and the worker thread (I was forced to use the win32 api in the worker thread since QStorageInfo wasn't reentrant) and I could easily foresee QPair being used in such a way as well.
                                      Thanks ! That might finalize this thread permanently :)

                                      kshegunovK 1 Reply Last reply
                                      0
                                      • C Crag_Hack

                                        Another related question I conjured up - how come some Qt classes aren't reeentrant that would be quite more useful if they were? I.E. QPair, QStorageInfo. My program makes use of drive storage info in both the main GUI thread and the worker thread (I was forced to use the win32 api in the worker thread since QStorageInfo wasn't reentrant) and I could easily foresee QPair being used in such a way as well.
                                        Thanks ! That might finalize this thread permanently :)

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

                                        QPair is reentrant, if the docs don't state it, then it's a "bug" in the documentation, please file it as such.

                                        As for QStorageInfo - I don't know if it's reentrant or not, I would have to check the source to find out for sure, but usually the class not being reentrant is due to the underlying API architecture (e.g. the widget classes).

                                        Read and abide by the Qt Code of Conduct

                                        1 Reply Last reply
                                        0
                                        • C Offline
                                          C Offline
                                          Crag_Hack
                                          wrote on last edited by
                                          #35

                                          Thanks. Perhaps they are both bugs - I would think a useful class that would have any possibility of being used in multiple threads like QStorageInfo would most definitely be reentrant. Is there another factor at play here besides utility?

                                          kshegunovK 2 Replies 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