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. Global static QPixmapCache in Qt internals
Forum Updated to NodeBB v4.3 + New Features

Global static QPixmapCache in Qt internals

Scheduled Pinned Locked Moved Unsolved General and Desktop
34 Posts 7 Posters 4.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.
  • Chris KawaC Offline
    Chris KawaC Offline
    Chris Kawa
    Lifetime Qt Champion
    wrote on last edited by Chris Kawa
    #13

    I reproduced this on Windows and the message about timers comes from a destructor of a static QPixmapCache object that happens on the main() thread. That's not something the user's code does. It's in Qt's internals.

    Right, so remember the rule that no QObject should outlive the application object and this means no static QObjects? Apparently Qt itself doesn't respect that rule and also creates static objects that run code in the main thread no matter where the application object is created :/

    I would consider this a Qt bug and expect it to crash all over the place.

    EDIT: I missed that JKSH already mentioned this, but yeah, this seems to be the culprit.

    kshegunovK 1 Reply Last reply
    3
    • Chris KawaC Chris Kawa

      I reproduced this on Windows and the message about timers comes from a destructor of a static QPixmapCache object that happens on the main() thread. That's not something the user's code does. It's in Qt's internals.

      Right, so remember the rule that no QObject should outlive the application object and this means no static QObjects? Apparently Qt itself doesn't respect that rule and also creates static objects that run code in the main thread no matter where the application object is created :/

      I would consider this a Qt bug and expect it to crash all over the place.

      EDIT: I missed that JKSH already mentioned this, but yeah, this seems to be the culprit.

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

      @Chris-Kawa said in QApplication in std::thread:

      I reproduced this on Windows and the message about timers comes from a destructor of a static QPixmapCache object that happens on the main() thread. That's not something the user's code does. It's in Qt's internals.

      Hm, interesting. Do you have a woboq location?

      Right, so remember the rule that no QObject should outlive the application object and this means no static QObjects?
      Apparently Qt itself doesn't respect that rule and also creates static objects that run code in the main thread no matter where the application object is created :/

      Yeah. Not living up to its own expectations it seems. :(

      I would consider this a Qt bug and expect it to crash all over the place.

      Me too, which is what I wrote somewhere upstairs - this should be fixed at the vendor side.

      Read and abide by the Qt Code of Conduct

      Chris KawaC 1 Reply Last reply
      1
      • kshegunovK kshegunov

        @Chris-Kawa said in QApplication in std::thread:

        I reproduced this on Windows and the message about timers comes from a destructor of a static QPixmapCache object that happens on the main() thread. That's not something the user's code does. It's in Qt's internals.

        Hm, interesting. Do you have a woboq location?

        Right, so remember the rule that no QObject should outlive the application object and this means no static QObjects?
        Apparently Qt itself doesn't respect that rule and also creates static objects that run code in the main thread no matter where the application object is created :/

        Yeah. Not living up to its own expectations it seems. :(

        I would consider this a Qt bug and expect it to crash all over the place.

        Me too, which is what I wrote somewhere upstairs - this should be fixed at the vendor side.

        Chris KawaC Offline
        Chris KawaC Offline
        Chris Kawa
        Lifetime Qt Champion
        wrote on last edited by Chris Kawa
        #15

        @kshegunov said in QApplication in std::thread:

        Hm, interesting. Do you have a woboq location?

        Instance declaration is here:
        https://code.woboq.org/qt5/qtbase/src/gui/image/qpixmapcache.cpp.html#pm_cache

        And here's Windows with MSVC crash callstack on exit:

        1   QPMCache::~QPMCache                                                                                   qpixmapcache.cpp 269
        2   ``anonymous namespace'::Q_QGS_pm_cache::innerFunction'::`2'::Holder::~Holder                          Qt5Guid             
        3   ``anonymous namespace'::Q_QGS_pm_cache::innerFunction'::`2'::`dynamic atexit destructor for 'holder'' Qt5Guid             
        4   initterm_e                                                                                            ucrtbased           
        5   initterm_e                                                                                            ucrtbased           
        6   initterm_e                                                                                            ucrtbased           
        7   execute_onexit_table                                                                                  ucrtbased           
        8   __scrt_dllmain_uninitialize_c                                                                         utility.cpp      399
        9   dllmain_crt_process_detach                                                                            dll_dllmain.cpp  182
        10  dllmain_crt_dispatch                                                                                  dll_dllmain.cpp  220
        11  dllmain_dispatch                                                                                      dll_dllmain.cpp  293
        12  _DllMainCRTStartup                                                                                    dll_dllmain.cpp  335
        13  RtlActivateActivationContextUnsafeFast                                                                ntdll               
        14  LdrShutdownProcess                                                                                    ntdll               
        15  RtlExitUserProcess                                                                                    ntdll               
        16  FatalExit                                                                                             KERNEL32            
        17  wassert                                                                                               ucrtbased           
        18  wassert                                                                                               ucrtbased           
        19  exit                                                                                                  ucrtbased           
        20  __scrt_common_main_seh                                                                                exe_common.inl   297
        

        I used this simplified code:

        int main(int argc, char *argv[])
        {
            std::thread thr([](int argc, char *argv[])
            {
                QApplication a(argc, argv);
                QPushButton btn("Push");
                btn.show();
                a.exec();
            }, argc, argv);
        
            thr.join();
        }
        
        kshegunovK 1 Reply Last reply
        2
        • Chris KawaC Chris Kawa

          @kshegunov said in QApplication in std::thread:

          Hm, interesting. Do you have a woboq location?

          Instance declaration is here:
          https://code.woboq.org/qt5/qtbase/src/gui/image/qpixmapcache.cpp.html#pm_cache

          And here's Windows with MSVC crash callstack on exit:

          1   QPMCache::~QPMCache                                                                                   qpixmapcache.cpp 269
          2   ``anonymous namespace'::Q_QGS_pm_cache::innerFunction'::`2'::Holder::~Holder                          Qt5Guid             
          3   ``anonymous namespace'::Q_QGS_pm_cache::innerFunction'::`2'::`dynamic atexit destructor for 'holder'' Qt5Guid             
          4   initterm_e                                                                                            ucrtbased           
          5   initterm_e                                                                                            ucrtbased           
          6   initterm_e                                                                                            ucrtbased           
          7   execute_onexit_table                                                                                  ucrtbased           
          8   __scrt_dllmain_uninitialize_c                                                                         utility.cpp      399
          9   dllmain_crt_process_detach                                                                            dll_dllmain.cpp  182
          10  dllmain_crt_dispatch                                                                                  dll_dllmain.cpp  220
          11  dllmain_dispatch                                                                                      dll_dllmain.cpp  293
          12  _DllMainCRTStartup                                                                                    dll_dllmain.cpp  335
          13  RtlActivateActivationContextUnsafeFast                                                                ntdll               
          14  LdrShutdownProcess                                                                                    ntdll               
          15  RtlExitUserProcess                                                                                    ntdll               
          16  FatalExit                                                                                             KERNEL32            
          17  wassert                                                                                               ucrtbased           
          18  wassert                                                                                               ucrtbased           
          19  exit                                                                                                  ucrtbased           
          20  __scrt_common_main_seh                                                                                exe_common.inl   297
          

          I used this simplified code:

          int main(int argc, char *argv[])
          {
              std::thread thr([](int argc, char *argv[])
              {
                  QApplication a(argc, argv);
                  QPushButton btn("Push");
                  btn.show();
                  a.exec();
              }, argc, argv);
          
              thr.join();
          }
          
          kshegunovK Offline
          kshegunovK Offline
          kshegunov
          Moderators
          wrote on last edited by
          #16

          Yes, this is constructed appropriately, however the deallocation should've been tied to the QCoreApplication::aboutToQuit. I doubt anyone is going to bother fixing it though, I'm not sure if it's not going to be discarded with "this is unsupported" even ...

          Read and abide by the Qt Code of Conduct

          JKSHJ 1 Reply Last reply
          0
          • kshegunovK kshegunov

            Yes, this is constructed appropriately, however the deallocation should've been tied to the QCoreApplication::aboutToQuit. I doubt anyone is going to bother fixing it though, I'm not sure if it's not going to be discarded with "this is unsupported" even ...

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

            Good detective work, @Chris-Kawa!

            I encountered this a few years ago but had forgotten most of the details.

            @kshegunov said in Global static QPixmapCache in Qt internals:

            Yes, this is constructed appropriately, however the deallocation should've been tied to the QCoreApplication::aboutToQuit. I doubt anyone is going to bother fixing it though, I'm not sure if it's not going to be discarded with "this is unsupported" even ...

            Since a QPixmap requires a QGuiApplication, would a simple(?) and correct fix be to allocate the QPixmapCache in the QGuiApplication constructor, and deallocate it from the QGuiApplication destructor?

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

            kshegunovK 1 Reply Last reply
            0
            • JKSHJ JKSH

              Good detective work, @Chris-Kawa!

              I encountered this a few years ago but had forgotten most of the details.

              @kshegunov said in Global static QPixmapCache in Qt internals:

              Yes, this is constructed appropriately, however the deallocation should've been tied to the QCoreApplication::aboutToQuit. I doubt anyone is going to bother fixing it though, I'm not sure if it's not going to be discarded with "this is unsupported" even ...

              Since a QPixmap requires a QGuiApplication, would a simple(?) and correct fix be to allocate the QPixmapCache in the QGuiApplication constructor, and deallocate it from the QGuiApplication destructor?

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

              Possibly. Or it can be a pseudo-singleton (similarly to QCoreApplication) and be initialized on demand in the instance retrieving function (dropping the global static that it currently uses). You could poke Thiago, but as written, I wouldn't hold my breath.

              Read and abide by the Qt Code of Conduct

              jeremy_kJ 1 Reply Last reply
              0
              • Christian EhrlicherC Online
                Christian EhrlicherC Online
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by Christian Ehrlicher
                #19

                There are some reports about such an issue:
                https://bugreports.qt.io/browse/QTBUG-48709
                https://bugreports.qt.io/browse/QTBUG-21807

                And it does not crash here for me on Linux and Windows (MSVC, debug-build) with 5.15.x

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

                kshegunovK 1 Reply Last reply
                0
                • Christian EhrlicherC Christian Ehrlicher

                  There are some reports about such an issue:
                  https://bugreports.qt.io/browse/QTBUG-48709
                  https://bugreports.qt.io/browse/QTBUG-21807

                  And it does not crash here for me on Linux and Windows (MSVC, debug-build) with 5.15.x

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

                  @Christian-Ehrlicher said in Global static QPixmapCache in Qt internals:

                  And it does not crash here for me on Linux and Windows (MSVC, debug-build) with 5.15.x

                  We are talking about the QTimers from another thread message. JKSH, split the threads. The other stuff (the supposed crash) contines to befuddle me.

                  Read and abide by the Qt Code of Conduct

                  1 Reply Last reply
                  0
                  • Christian EhrlicherC Online
                    Christian EhrlicherC Online
                    Christian Ehrlicher
                    Lifetime Qt Champion
                    wrote on last edited by
                    #21

                    I also don't have a warning about the timer with the testcase on windows/msvc :)

                    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
                    0
                    • S Offline
                      S Offline
                      Suthiro
                      wrote on last edited by
                      #22

                      @kshegunov

                      We are talking about the QTimers from another thread message. JKSH, split the threads. The other stuff (the supposed crash) contines to befuddle me.

                      I don't know how exactly the crash in the original thread is connected with this. However, the crash and the message about timers are appearing together. They appear after any interaction with simple QPushButton. Using deleteLater() as suggested by @JKSH solves the crash, but the message persists.

                      @Christian-Ehrlicher said in Global static QPixmapCache in Qt internals:

                      And it does not crash here for me on Linux and Windows (MSVC, debug-build) with 5.15.x

                      To clarify: crash appears only when one tries to unload a library with QApplication inside. The library in my case is loaded by lua.exe, but I doubt it is lua-related problem.

                      1 Reply Last reply
                      0
                      • kshegunovK kshegunov

                        Possibly. Or it can be a pseudo-singleton (similarly to QCoreApplication) and be initialized on demand in the instance retrieving function (dropping the global static that it currently uses). You could poke Thiago, but as written, I wouldn't hold my breath.

                        jeremy_kJ Online
                        jeremy_kJ Online
                        jeremy_k
                        wrote on last edited by
                        #23

                        @kshegunov said in Global static QPixmapCache in Qt internals:

                        Possibly. Or it can be a pseudo-singleton (similarly to QCoreApplication) and be initialized on demand in the instance retrieving function (dropping the global static that it currently uses). You could poke Thiago, but as written, I wouldn't hold my breath.

                        That sounds like a source and binary compatibility break, unless instance() is used from within the existing static functions.

                        A thread_local version would be another solution, that could be implemented without changing any user source code. Keep the global static interface object for binary compatibility, and move the actual QObject-based implementation to thread_local storage for the gui thread.

                        The QPixmapCache documentation already says that the cache is only usable from the "application's main thread".

                        Asking a question about code? http://eel.is/iso-c++/testcase/

                        kshegunovK 1 Reply Last reply
                        0
                        • jeremy_kJ jeremy_k

                          @kshegunov said in Global static QPixmapCache in Qt internals:

                          Possibly. Or it can be a pseudo-singleton (similarly to QCoreApplication) and be initialized on demand in the instance retrieving function (dropping the global static that it currently uses). You could poke Thiago, but as written, I wouldn't hold my breath.

                          That sounds like a source and binary compatibility break, unless instance() is used from within the existing static functions.

                          A thread_local version would be another solution, that could be implemented without changing any user source code. Keep the global static interface object for binary compatibility, and move the actual QObject-based implementation to thread_local storage for the gui thread.

                          The QPixmapCache documentation already says that the cache is only usable from the "application's main thread".

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

                          @jeremy_k said in Global static QPixmapCache in Qt internals:

                          That sounds like a source and binary compatibility break, unless instance() is used from within the existing static functions.

                          Adding non-virtual functions doesn't brake API or ABI compatibility. Also this is an internal member, any global getter function could do, it's not really necessary to expose it to the user.

                          A thread_local version would be another solution, that could be implemented without changing any user source code. Keep the global static interface object for binary compatibility, and move the actual QObject-based implementation to thread_local storage for the gui thread.

                          The QPixmapCache documentation already says that the cache is only usable from the "application's main thread".

                          It's an internal class, I didn't intend to modify the QPixmapCache to begin with. (see the woboq link in Chris' post)

                          Read and abide by the Qt Code of Conduct

                          jeremy_kJ 1 Reply Last reply
                          0
                          • kshegunovK kshegunov

                            @jeremy_k said in Global static QPixmapCache in Qt internals:

                            That sounds like a source and binary compatibility break, unless instance() is used from within the existing static functions.

                            Adding non-virtual functions doesn't brake API or ABI compatibility. Also this is an internal member, any global getter function could do, it's not really necessary to expose it to the user.

                            A thread_local version would be another solution, that could be implemented without changing any user source code. Keep the global static interface object for binary compatibility, and move the actual QObject-based implementation to thread_local storage for the gui thread.

                            The QPixmapCache documentation already says that the cache is only usable from the "application's main thread".

                            It's an internal class, I didn't intend to modify the QPixmapCache to begin with. (see the woboq link in Chris' post)

                            jeremy_kJ Online
                            jeremy_kJ Online
                            jeremy_k
                            wrote on last edited by
                            #25

                            @kshegunov said in Global static QPixmapCache in Qt internals:

                            @jeremy_k said in Global static QPixmapCache in Qt internals:

                            That sounds like a source and binary compatibility break, unless instance() is used from within the existing static functions.

                            Adding non-virtual functions doesn't brake API or ABI compatibility. Also this is an internal member, any global getter function could do, it's not really necessary to expose it to the user.

                            I had read it as a suggestion to introduce a static QPixmapCache::instance(), and make the currently static QPixmapCache member functions non-static. I autocompleted too much.

                            A thread_local version would be another solution, that could be implemented without changing any user source code. Keep the global static interface object for binary compatibility, and move the actual QObject-based implementation to thread_local storage for the gui thread.

                            The QPixmapCache documentation already says that the cache is only usable from the "application's main thread".

                            It's an internal class, I didn't intend to modify the QPixmapCache to begin with. (see the woboq link in Chris' post)

                            I saw, and if I interpreted correctly, the issue is that the global static QPixmapCache and its internal QObject based implementation will be destroyed from the C++ main thread when main() exits. The destruction of the internal implementation object could be removed from the public QPixmapCache destructor, but the question is where to destroy it while maintaining the current intended behavior. Making the internal object (or a wrapper) thread local in the gui thread solves destruction at a point where the cache can't see further use anyway.

                            Asking a question about code? http://eel.is/iso-c++/testcase/

                            kshegunovK 1 Reply Last reply
                            0
                            • jeremy_kJ jeremy_k

                              @kshegunov said in Global static QPixmapCache in Qt internals:

                              @jeremy_k said in Global static QPixmapCache in Qt internals:

                              That sounds like a source and binary compatibility break, unless instance() is used from within the existing static functions.

                              Adding non-virtual functions doesn't brake API or ABI compatibility. Also this is an internal member, any global getter function could do, it's not really necessary to expose it to the user.

                              I had read it as a suggestion to introduce a static QPixmapCache::instance(), and make the currently static QPixmapCache member functions non-static. I autocompleted too much.

                              A thread_local version would be another solution, that could be implemented without changing any user source code. Keep the global static interface object for binary compatibility, and move the actual QObject-based implementation to thread_local storage for the gui thread.

                              The QPixmapCache documentation already says that the cache is only usable from the "application's main thread".

                              It's an internal class, I didn't intend to modify the QPixmapCache to begin with. (see the woboq link in Chris' post)

                              I saw, and if I interpreted correctly, the issue is that the global static QPixmapCache and its internal QObject based implementation will be destroyed from the C++ main thread when main() exits. The destruction of the internal implementation object could be removed from the public QPixmapCache destructor, but the question is where to destroy it while maintaining the current intended behavior. Making the internal object (or a wrapper) thread local in the gui thread solves destruction at a point where the cache can't see further use anyway.

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

                              @jeremy_k said in Global static QPixmapCache in Qt internals:

                              I saw, and if I interpreted correctly, the issue is that the global static QPixmapCache and its internal QObject based implementation will be destroyed from the C++ main thread when main() exits.

                              Correct, but only with the allowance that we are talking about the QPMCache instance (which is some internal class).

                              The destruction of the internal implementation object could be removed from the public QPixmapCache destructor, but the question is where to destroy it while maintaining the current intended behavior.

                              As I wrote: QCoreApplication::aboutToQuit is one possible such point. The problem with that solution is that it won't set the nullptr of the global pointer, which in turn is going to lead to a crash if the application object is recreated. It shouldn't get recreated, but I've seen code that relies on that (believe or not). With any API the first thing you get is hidden use cases, sadly.

                              Making the internal object (or a wrapper) thread local in the gui thread solves destruction at a point where the cache can't see further use anyway.

                              I don't follow. The instance is created dynamically and on demand, and from some thread unknown at the point of declaration. How does specifying a thread local storage helps here, the pointer to the object is global (and I assume used from many a place)?

                              Read and abide by the Qt Code of Conduct

                              jeremy_kJ 1 Reply Last reply
                              0
                              • kshegunovK kshegunov

                                @jeremy_k said in Global static QPixmapCache in Qt internals:

                                I saw, and if I interpreted correctly, the issue is that the global static QPixmapCache and its internal QObject based implementation will be destroyed from the C++ main thread when main() exits.

                                Correct, but only with the allowance that we are talking about the QPMCache instance (which is some internal class).

                                The destruction of the internal implementation object could be removed from the public QPixmapCache destructor, but the question is where to destroy it while maintaining the current intended behavior.

                                As I wrote: QCoreApplication::aboutToQuit is one possible such point. The problem with that solution is that it won't set the nullptr of the global pointer, which in turn is going to lead to a crash if the application object is recreated. It shouldn't get recreated, but I've seen code that relies on that (believe or not). With any API the first thing you get is hidden use cases, sadly.

                                Making the internal object (or a wrapper) thread local in the gui thread solves destruction at a point where the cache can't see further use anyway.

                                I don't follow. The instance is created dynamically and on demand, and from some thread unknown at the point of declaration. How does specifying a thread local storage helps here, the pointer to the object is global (and I assume used from many a place)?

                                jeremy_kJ Online
                                jeremy_kJ Online
                                jeremy_k
                                wrote on last edited by
                                #27

                                @kshegunov said in Global static QPixmapCache in Qt internals:

                                @jeremy_k said in Global static QPixmapCache in Qt internals:

                                I saw, and if I interpreted correctly, the issue is that the global static QPixmapCache and its internal QObject based implementation will be destroyed from the C++ main thread when main() exits.

                                Correct, but only with the allowance that we are talking about the QPMCache instance (which is some internal class).

                                Yes. We seem to be talking around the same point.

                                The destruction of the internal implementation object could be removed from the public QPixmapCache destructor, but the question is where to destroy it while maintaining the current intended behavior.

                                As I wrote: QCoreApplication::aboutToQuit is one possible such point. The problem with that solution is that it won't set the nullptr of the global pointer, which in turn is going to lead to a crash if the application object is recreated. It shouldn't get recreated, but I've seen code that relies on that (believe or not). With any API the first thing you get is hidden use cases, sadly.

                                Making the internal object (or a wrapper) thread local in the gui thread solves destruction at a point where the cache can't see further use anyway.

                                I don't follow. The instance is created dynamically and on demand, and from some thread unknown at the point of declaration. How does specifying a thread local storage helps here, the pointer to the object is global (and I assume used from many a place)?

                                Using QCoreApplication::aboutToQuit would change the behavior for applications that repeatedly instantiate and destroy the application instance, and it would add an opportunity to make a mistake for applications that don't use QCoreApplication::exec().

                                Using a thread local object keeps this into RAII territory. The only difference from the current global static is that destruction happens in the relevant thread rather than in the main() thread.

                                How does the cache managing object tell that it is in the gui thread? If the first application instance must be created before cache use, QThread::currentThread()->threadId() == QCoreApplication::instance()->thread()->threadId() could work. I don't know if creating the application first is currently required.

                                Asking a question about code? http://eel.is/iso-c++/testcase/

                                kshegunovK 1 Reply Last reply
                                0
                                • jeremy_kJ jeremy_k

                                  @kshegunov said in Global static QPixmapCache in Qt internals:

                                  @jeremy_k said in Global static QPixmapCache in Qt internals:

                                  I saw, and if I interpreted correctly, the issue is that the global static QPixmapCache and its internal QObject based implementation will be destroyed from the C++ main thread when main() exits.

                                  Correct, but only with the allowance that we are talking about the QPMCache instance (which is some internal class).

                                  Yes. We seem to be talking around the same point.

                                  The destruction of the internal implementation object could be removed from the public QPixmapCache destructor, but the question is where to destroy it while maintaining the current intended behavior.

                                  As I wrote: QCoreApplication::aboutToQuit is one possible such point. The problem with that solution is that it won't set the nullptr of the global pointer, which in turn is going to lead to a crash if the application object is recreated. It shouldn't get recreated, but I've seen code that relies on that (believe or not). With any API the first thing you get is hidden use cases, sadly.

                                  Making the internal object (or a wrapper) thread local in the gui thread solves destruction at a point where the cache can't see further use anyway.

                                  I don't follow. The instance is created dynamically and on demand, and from some thread unknown at the point of declaration. How does specifying a thread local storage helps here, the pointer to the object is global (and I assume used from many a place)?

                                  Using QCoreApplication::aboutToQuit would change the behavior for applications that repeatedly instantiate and destroy the application instance, and it would add an opportunity to make a mistake for applications that don't use QCoreApplication::exec().

                                  Using a thread local object keeps this into RAII territory. The only difference from the current global static is that destruction happens in the relevant thread rather than in the main() thread.

                                  How does the cache managing object tell that it is in the gui thread? If the first application instance must be created before cache use, QThread::currentThread()->threadId() == QCoreApplication::instance()->thread()->threadId() could work. I don't know if creating the application first is currently required.

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

                                  @jeremy_k said in Global static QPixmapCache in Qt internals:

                                  Using a thread local object keeps this into RAII territory. The only difference from the current global static is that destruction happens in the relevant thread rather than in the main() thread.

                                  Ehm, the object, currently, is created in the heap, is it not? Or perhaps I'm misunderstanding what you mean exactly.

                                  @jeremy_k said in Global static QPixmapCache in Qt internals:

                                  I don't know if creating the application first is currently required.

                                  Yes, it is, but also no QObject shall outlive the QCoreApplication instance is part of the rule, which is exactly what's happening in this case.

                                  PS.

                                  How does the cache managing object tell that it is in the gui thread?

                                  When a QObject is created it stores the reference to the creating thread internally. When the destructor's run that reference's thread id is checked against the current thread id, if they don't match you know you're destroying objects from another thread. This is where this warning is generated.

                                  Read and abide by the Qt Code of Conduct

                                  jeremy_kJ 1 Reply Last reply
                                  1
                                  • kshegunovK kshegunov

                                    @jeremy_k said in Global static QPixmapCache in Qt internals:

                                    Using a thread local object keeps this into RAII territory. The only difference from the current global static is that destruction happens in the relevant thread rather than in the main() thread.

                                    Ehm, the object, currently, is created in the heap, is it not? Or perhaps I'm misunderstanding what you mean exactly.

                                    @jeremy_k said in Global static QPixmapCache in Qt internals:

                                    I don't know if creating the application first is currently required.

                                    Yes, it is, but also no QObject shall outlive the QCoreApplication instance is part of the rule, which is exactly what's happening in this case.

                                    PS.

                                    How does the cache managing object tell that it is in the gui thread?

                                    When a QObject is created it stores the reference to the creating thread internally. When the destructor's run that reference's thread id is checked against the current thread id, if they don't match you know you're destroying objects from another thread. This is where this warning is generated.

                                    jeremy_kJ Online
                                    jeremy_kJ Online
                                    jeremy_k
                                    wrote on last edited by
                                    #29

                                    @kshegunov said in Global static QPixmapCache in Qt internals:

                                    @jeremy_k said in Global static QPixmapCache in Qt internals:

                                    Using a thread local object keeps this into RAII territory. The only difference from the current global static is that destruction happens in the relevant thread rather than in the main() thread.

                                    Ehm, the object, currently, is created in the heap, is it not? Or perhaps I'm misunderstanding what you mean exactly.

                                    IIRC, it is created and destroyed by a QGlobalStatic.

                                    @jeremy_k said in Global static QPixmapCache in Qt internals:

                                    I don't know if creating the application first is currently required.

                                    Yes, it is, but also no QObject shall outlive the QCoreApplication instance is part of the rule, which is exactly what's happening in this case.

                                    The cache object also outlives a stack allocated QCoreApplication when the gui thread is the main thread.

                                    I'm looking for and not finding a reference to the rules about QCoreApplication versus QObject lifetimes. There used to be a concise list, if I didn't imagine it.

                                    Asking a question about code? http://eel.is/iso-c++/testcase/

                                    kshegunovK 1 Reply Last reply
                                    0
                                    • jeremy_kJ jeremy_k

                                      @kshegunov said in Global static QPixmapCache in Qt internals:

                                      @jeremy_k said in Global static QPixmapCache in Qt internals:

                                      Using a thread local object keeps this into RAII territory. The only difference from the current global static is that destruction happens in the relevant thread rather than in the main() thread.

                                      Ehm, the object, currently, is created in the heap, is it not? Or perhaps I'm misunderstanding what you mean exactly.

                                      IIRC, it is created and destroyed by a QGlobalStatic.

                                      @jeremy_k said in Global static QPixmapCache in Qt internals:

                                      I don't know if creating the application first is currently required.

                                      Yes, it is, but also no QObject shall outlive the QCoreApplication instance is part of the rule, which is exactly what's happening in this case.

                                      The cache object also outlives a stack allocated QCoreApplication when the gui thread is the main thread.

                                      I'm looking for and not finding a reference to the rules about QCoreApplication versus QObject lifetimes. There used to be a concise list, if I didn't imagine it.

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

                                      @jeremy_k said in Global static QPixmapCache in Qt internals:

                                      IIRC, it is created and destroyed by a QGlobalStatic.

                                      Yes, correct. So you want to make the QGlobalStatic instance thread local then?

                                      @jeremy_k said in Global static QPixmapCache in Qt internals:

                                      The cache object also outlives a stack allocated QCoreApplication when the gui thread is the main thread.

                                      Yes, but since they're created and destroyed in the same thread the message doesn't fire up. It's wrong, it's just hidden.

                                      @jeremy_k said in Global static QPixmapCache in Qt internals:

                                      I'm looking for and not finding a reference to the rules about QCoreApplication versus QObject lifetimes. There used to be a concise list, if I didn't imagine it.

                                      I don't remember such a list, but this is a direct quote of Thiago[1]:

                                      And QCoreApplication should be the first QObject created and last destroyed.

                                      Read and abide by the Qt Code of Conduct

                                      jeremy_kJ 1 Reply Last reply
                                      0
                                      • kshegunovK kshegunov

                                        @jeremy_k said in Global static QPixmapCache in Qt internals:

                                        IIRC, it is created and destroyed by a QGlobalStatic.

                                        Yes, correct. So you want to make the QGlobalStatic instance thread local then?

                                        @jeremy_k said in Global static QPixmapCache in Qt internals:

                                        The cache object also outlives a stack allocated QCoreApplication when the gui thread is the main thread.

                                        Yes, but since they're created and destroyed in the same thread the message doesn't fire up. It's wrong, it's just hidden.

                                        @jeremy_k said in Global static QPixmapCache in Qt internals:

                                        I'm looking for and not finding a reference to the rules about QCoreApplication versus QObject lifetimes. There used to be a concise list, if I didn't imagine it.

                                        I don't remember such a list, but this is a direct quote of Thiago[1]:

                                        And QCoreApplication should be the first QObject created and last destroyed.

                                        jeremy_kJ Online
                                        jeremy_kJ Online
                                        jeremy_k
                                        wrote on last edited by
                                        #31

                                        @kshegunov said in Global static QPixmapCache in Qt internals:

                                        @jeremy_k said in Global static QPixmapCache in Qt internals:

                                        IIRC, it is created and destroyed by a QGlobalStatic.

                                        Yes, correct. So you want to make the QGlobalStatic instance thread local then?

                                        That would be nice. QTheadLocalStatic. I don't see a lot of thread_local in Qt 6 base.

                                        @jeremy_k said in Global static QPixmapCache in Qt internals:

                                        I'm looking for and not finding a reference to the rules about QCoreApplication versus QObject lifetimes. There used to be a concise list, if I didn't imagine it.

                                        I don't remember such a list, but this is a direct quote of Thiago[1]:

                                        And QCoreApplication should be the first QObject created and last destroyed.

                                        It's not the reference I was thinking of, but thanks.

                                        Asking a question about code? http://eel.is/iso-c++/testcase/

                                        kshegunovK 1 Reply Last reply
                                        0
                                        • jeremy_kJ jeremy_k

                                          @kshegunov said in Global static QPixmapCache in Qt internals:

                                          @jeremy_k said in Global static QPixmapCache in Qt internals:

                                          IIRC, it is created and destroyed by a QGlobalStatic.

                                          Yes, correct. So you want to make the QGlobalStatic instance thread local then?

                                          That would be nice. QTheadLocalStatic. I don't see a lot of thread_local in Qt 6 base.

                                          @jeremy_k said in Global static QPixmapCache in Qt internals:

                                          I'm looking for and not finding a reference to the rules about QCoreApplication versus QObject lifetimes. There used to be a concise list, if I didn't imagine it.

                                          I don't remember such a list, but this is a direct quote of Thiago[1]:

                                          And QCoreApplication should be the first QObject created and last destroyed.

                                          It's not the reference I was thinking of, but thanks.

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

                                          @jeremy_k said in Global static QPixmapCache in Qt internals:

                                          That would be nice. QTheadLocalStatic. I don't see a lot of thread_local in Qt 6 base.

                                          Because it has very niche uses to begin with. Making the mentioned object thread local implies an instance being created for each thread that runs. It could work, but I'm not convinced it's necessary to create the wrapper object for each thread Qt or the user starts. Granted it's just some pointer wrapper, but still ... there should be a cleaner way, I think.

                                          PS
                                          We are overengineering the solution. The pixmap cache is only supposed to work from one thread and the GUI one at that. You just revert to a plain pointer and define an inline function that creates the object if not there. (It also connects a lambda for deletion and clearing the pointer itself). The uses seem to be limited only to the QPixmapCache implementation itself.

                                          PS 2
                                          Alternatively you convert it to QPointer and create the object in the QPixmapCache constructor where you also connect the QCoreApplication::aboutToQuit to the QObject::deleteLater for the internal object.

                                          Read and abide by the Qt Code of Conduct

                                          JKSHJ 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