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 2.6k 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.
  • K kshegunov
    28 Apr 2021, 06:08

    @J-Hilk said in QApplication in std::thread:

    @JKSH this actually crashes for me on btn.show()

    That's expected. MacOS does not support plugging into the event loop from a thread different from main(). Should work on linux and windows, though.

    J Offline
    J Offline
    J.Hilk
    Moderators
    wrote on 28 Apr 2021, 06:11 last edited by
    #8

    @kshegunov Apple does a lot of funky stuff, in that regard, let me fire up my vm


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


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

    1 Reply Last reply
    2
    • K kshegunov
      28 Apr 2021, 06:10

      @JKSH said in QApplication in std::thread:

      Ah, right... I thought the Debug build would suffice. Don't have a dev build right now.

      Not once in a universe lifetime.

      @JKSH said in QApplication in std::thread:

      Might be Windows-specific.

      Possibly. Unfortunately I don't have windows on hand (or rather I'm too lazy now to boot into it). Maybe, I'll check it later.

      J Offline
      J Offline
      JKSH
      Moderators
      wrote on 28 Apr 2021, 06:14 last edited by JKSH
      #9

      @kshegunov said in QApplication in std::thread:

      Not once in a universe lifetime.

      Duly noted :-D

      But before we get too sidetracked: @Suthiro's main issue isn't the message about timers. Rather, it's the crash which I believe is caused by delete m_qPlotsControl; (see https://stackoverflow.com/questions/67257329/weird-qpushbutton-bug ).

      I believe it is fixable with m_qPlotsControl->deleteLater();... but that needs to be done before QApplication::exec() returns, because QDeferredDeleteEvent won't be processed without an event loop.

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

      J K 2 Replies Last reply 28 Apr 2021, 06:27
      0
      • J JKSH
        28 Apr 2021, 06:14

        @kshegunov said in QApplication in std::thread:

        Not once in a universe lifetime.

        Duly noted :-D

        But before we get too sidetracked: @Suthiro's main issue isn't the message about timers. Rather, it's the crash which I believe is caused by delete m_qPlotsControl; (see https://stackoverflow.com/questions/67257329/weird-qpushbutton-bug ).

        I believe it is fixable with m_qPlotsControl->deleteLater();... but that needs to be done before QApplication::exec() returns, because QDeferredDeleteEvent won't be processed without an event loop.

        J Offline
        J Offline
        J.Hilk
        Moderators
        wrote on 28 Apr 2021, 06:27 last edited by
        #10

        @JKSH Ok I can reproduce it as well, (on the VM) Qt 15.3 & MSVC2019


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


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

        1 Reply Last reply
        1
        • J JKSH
          28 Apr 2021, 06:14

          @kshegunov said in QApplication in std::thread:

          Not once in a universe lifetime.

          Duly noted :-D

          But before we get too sidetracked: @Suthiro's main issue isn't the message about timers. Rather, it's the crash which I believe is caused by delete m_qPlotsControl; (see https://stackoverflow.com/questions/67257329/weird-qpushbutton-bug ).

          I believe it is fixable with m_qPlotsControl->deleteLater();... but that needs to be done before QApplication::exec() returns, because QDeferredDeleteEvent won't be processed without an event loop.

          K Offline
          K Offline
          kshegunov
          Moderators
          wrote on 28 Apr 2021, 06:31 last edited by
          #11

          @JKSH said in QApplication in std::thread:

          I believe it is fixable with m_qPlotsControl->deleteLater();... but that needs to be done before QApplication::exec() returns, because QDeferredDeleteEvent won't be processed without an event loop.

          I still don't understand this. For what reason should that be the case, and why would this generate a crash? I'm pretty sure deferred deletes are processed after the event loop has exited (see for example the QThread::finished -> QObject::deleteLater), but even if that weren't the case the QPushButton's destructor is going to be run before the thread actually finishes and before the application object's destructor's run (there's no difference between main() and any other function from c++'s point of view).

          Read and abide by the Qt Code of Conduct

          J 1 Reply Last reply 28 Apr 2021, 07:26
          0
          • J JKSH
            28 Apr 2021, 07:26

            [Forked from https://forum.qt.io/topic/126128/qapplication-in-std-thread -- Sorry, I messed up the order of posts when I did the fork; this top post should be further down]

            @kshegunov said in QApplication in std::thread:

            why would this generate a crash?

            Since the widget creates a timer in the background, then it's probably receiving background events/signals. delete could cause the event/signal handler to act on a dangling pointer -- that's how it could generate a crash. And that's why deleteLater() can fix the crash. (Alternatively, we could change from a heap-allocated widget to a stack-allocated widget)

            I'm pretty sure deferred deletes are processed after the event loop has exited (see for example the QThread::finished -> QObject::deleteLater)

            The code below prints "Bye" but not "Widget destroyed", proving that the Widget's destructor is not run:

            // widget.h
            #include <QWidget>
            
            class Widget : public QWidget
            {
                Q_OBJECT
            public:
                Widget(QWidget *parent = nullptr) : QWidget(parent) {}
                ~Widget(){ qDebug("Widget destroyed"); }
            };
            
            // main.cpp
            #include "widget.h"
            #include <QApplication>
            #include <chrono>
            #include <thread>
            
            using namespace std::chrono_literals;
            
            int main(int argc, char *argv[])
            {
                std::thread thr([&]
                {
                    QApplication a(argc, argv);
                    auto w = new Widget;
                    w->show();
                    a.exec();
            
                    // delete w; // This WILL run the Widget's destructor
            
                    w->deleteLater(); // This WON'T run the Widget's destructor
                });
            
                std::this_thread::sleep_for(5000ms);
            
                QMetaObject::invokeMethod(qApp, &QApplication::quit);
                thr.join();
            
                std::this_thread::sleep_for(5000ms);
                qDebug("Bye");
            }
            

            Anyway, I was trying to say that @Suthiro can't simply replace delete m_qPlotsControl; with m_qPlotsControl->deleteLater(); in-place at https://stackoverflow.com/questions/67257329/weird-qpushbutton-bug . Some re-shuffling is required.

            K Offline
            K Offline
            kshegunov
            Moderators
            wrote on 28 Apr 2021, 08:33 last edited by kshegunov
            #12

            @JKSH said in QApplication in std::thread:

            The code below prints "Bye" but not "Widget destroyed", proving that the Widget's destructor is not run:

            I meant connecting to the aboutToQuit signal, but anyhow it's not that important.

            Since the widget creates a timer in the background, then it's probably receiving background events/signals. delete could cause the event/signal handler to act on a dangling pointer -- that's how it could generate a crash.

            I think this shouldn't happen, but can't investigate it currently.

            Anyway, I was trying to say that @Suthiro can't simply replace delete m_qPlotsControl; with m_qPlotsControl->deleteLater(); in-place at https://stackoverflow.com/questions/67257329/weird-qpushbutton-bug . Some re-shuffling is required.

            I suppose, but that timer message should go away, otherwise the code can break at any moment (this applies to your code too - the one you mentioned where you get the warning).

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            0
            • C Offline
              C Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on 28 Apr 2021, 09:42 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.

              K 1 Reply Last reply 28 Apr 2021, 10:32
              3
              • C Chris Kawa
                28 Apr 2021, 09:42

                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.

                K Offline
                K Offline
                kshegunov
                Moderators
                wrote on 28 Apr 2021, 10:32 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

                C 1 Reply Last reply 28 Apr 2021, 10:59
                1
                • K kshegunov
                  28 Apr 2021, 10:32

                  @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.

                  C Offline
                  C Offline
                  Chris Kawa
                  Lifetime Qt Champion
                  wrote on 28 Apr 2021, 10:59 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();
                  }
                  
                  K 1 Reply Last reply 28 Apr 2021, 12:23
                  2
                  • C Chris Kawa
                    28 Apr 2021, 10:59

                    @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();
                    }
                    
                    K Offline
                    K Offline
                    kshegunov
                    Moderators
                    wrote on 28 Apr 2021, 12:23 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

                    J 1 Reply Last reply 28 Apr 2021, 16:57
                    0
                    • K kshegunov
                      28 Apr 2021, 12:23

                      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 ...

                      J Offline
                      J Offline
                      JKSH
                      Moderators
                      wrote on 28 Apr 2021, 16:57 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

                      K 1 Reply Last reply 28 Apr 2021, 17:36
                      0
                      • J JKSH
                        28 Apr 2021, 16:57

                        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?

                        K Offline
                        K Offline
                        kshegunov
                        Moderators
                        wrote on 28 Apr 2021, 17:36 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

                        J 1 Reply Last reply 28 Apr 2021, 21:45
                        0
                        • C Online
                          C Online
                          Christian Ehrlicher
                          Lifetime Qt Champion
                          wrote on 28 Apr 2021, 17:40 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

                          K 1 Reply Last reply 28 Apr 2021, 17:43
                          0
                          • C Christian Ehrlicher
                            28 Apr 2021, 17:40

                            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

                            K Offline
                            K Offline
                            kshegunov
                            Moderators
                            wrote on 28 Apr 2021, 17:43 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
                            • C Online
                              C Online
                              Christian Ehrlicher
                              Lifetime Qt Champion
                              wrote on 28 Apr 2021, 17:53 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 28 Apr 2021, 21:37 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
                                • K kshegunov
                                  28 Apr 2021, 17:36

                                  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.

                                  J Offline
                                  J Offline
                                  jeremy_k
                                  wrote on 28 Apr 2021, 21:45 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/

                                  K 1 Reply Last reply 28 Apr 2021, 22:54
                                  0
                                  • J jeremy_k
                                    28 Apr 2021, 21:45

                                    @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".

                                    K Offline
                                    K Offline
                                    kshegunov
                                    Moderators
                                    wrote on 28 Apr 2021, 22:54 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

                                    J 1 Reply Last reply 29 Apr 2021, 02:54
                                    0
                                    • K kshegunov
                                      28 Apr 2021, 22:54

                                      @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)

                                      J Offline
                                      J Offline
                                      jeremy_k
                                      wrote on 29 Apr 2021, 02:54 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/

                                      K 1 Reply Last reply 29 Apr 2021, 17:37
                                      0
                                      • J jeremy_k
                                        29 Apr 2021, 02:54

                                        @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.

                                        K Offline
                                        K Offline
                                        kshegunov
                                        Moderators
                                        wrote on 29 Apr 2021, 17:37 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

                                        J 1 Reply Last reply 29 Apr 2021, 18:10
                                        0
                                        • K kshegunov
                                          29 Apr 2021, 17:37

                                          @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)?

                                          J Offline
                                          J Offline
                                          jeremy_k
                                          wrote on 29 Apr 2021, 18:10 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/

                                          K 1 Reply Last reply 29 Apr 2021, 18:16
                                          0

                                          17/34

                                          28 Apr 2021, 16:57

                                          • Login

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