Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-75007

QML Singleton creation in multi-threaded application causes errors

    XMLWordPrintable

Details

    • Linux/X11

    Description

      When running multiple threads

      • each one having a QQmlEngine
      • each one running an identical QML file
      • each one calling a method which instanciates a singleton object (QML singleton)

      i get the following warnings and errors (not always):

      • std::bad_alloc exception and application crashes
      • Type conversion already registered from type ... to ...
      • TypeError: Property 'foo' of object Qst_QMLTYPE_1(0x7fcd84022b50) is not a function
      • Trying to construct an instance of an invalid type, type id: <some number>

      Please find attached a minimal test case that reproduces that behavior. Some of the warnings/errors go away if I protect QQmlComponent constructor and create() by a mutex. However, I think that this only masks the problem because it makes it less likely that both threads instantiate the singletons at the same time. The singleton objects are instantiated when the run() method in file.qml is invoked.

      Looks like this one hits several concurrency problems in the Qt meta type system and QML type loader.

      Here is the code:

      #include <QtCore>
      #include <QtQml>
      
      QMutex mutex;
      
      class Runnable : public QRunnable {
      public:
          virtual void run() final;
      };
      
      void Runnable::run() {
          QQmlEngine engine;
      //    QMutexLocker lock(&mutex);
          QQmlComponent component(&engine,QUrl::fromLocalFile("file.qml"));
          QObject* object = component.create(engine.rootContext());
      //    lock.unlock();
          Q_ASSERT(component.errors().isEmpty());
      
          QMetaObject::invokeMethod(object, "run");
      }
      
      void doSomething() {
          for (int i = 0; i < 12; i++) {
              QThreadPool::globalInstance()->start(new Runnable());
          }
          QThreadPool::globalInstance()->waitForDone();
          QCoreApplication::exit(0);
      }
      
      int main(int argc, char* argv[]) {
          QCoreApplication app(argc, argv);
          QThreadPool::globalInstance()->setMaxThreadCount(2);
          QTimer::singleShot(1, &doSomething);
          return app.exec();
      }
      
      // Qst.qml
      import QtQml 2.0
      pragma Singleton
      
      QtObject {
      
          function foo() {
              for (var i = 0; i < 1000; i++) {
      
              }
          }
      }
      

      Attachments

        Issue Links

          For Gerrit Dashboard: QTBUG-75007
          # Subject Branch Project Status CR V

          Activity

            People

              qt.team.quick.subscriptions Qt Quick and Widgets Team
              rweickelt Richard Weickelt
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:

                Gerrit Reviews

                  There are no open Gerrit changes