11

I'm trying to determine how calling QObject slots or Q_INVOKABLE methods from QML for a QObject that lives in another thread works, and whether or not its safe to do so.

Assume there's a MainThread and ThreadA. QObjectA lives in ThreadA. The QML engine/gui/everything lives in the MainThread. I expose QObjectA to the QML engine using

declarativeView->setContextProperty("someObj",ObjectA)

Now in a QML file, I call

someObj.someMethod();

Where someMethod is a slot or is Q_INVOKABLE. I'd like to know which thread actually executes the function. If it's MainThread, that would be a bad thing, and calling a method like that across threads would be dangerous. If it was executed by ThreadA however, all would be well.

Based on this documentation: http://doc.qt.nokia.com/4.7-snapshot/qtbinding.html, I'm assuming that QMetaObject::invokeMethod() is used to call the QObject function. That documentation (http://doc.qt.nokia.com/4.7-snapshot/qmetaobject.html#invokeMethod), shows that there are different connection types available, just like with Qt signals and slots.

I'd like to know if Qt's qml engine automagically chooses the right type for the situation when invoking C++ methods from QML across threads, and if so, calling methods for objects that live in other threads from QML is an acceptable practice.

Prismatic
  • 3,338
  • 5
  • 36
  • 59
  • You can use `qDebug() << "Main thread: " << QThread::currentThreadId();` to figure out where the function is running. As stated in some other comment, you should not assume that some non-documented behaviour will be consistent for future versions. – mozzbozz Nov 11 '14 at 13:29
  • You refere to Qt 4.7 docs. Are you using Qt 4.7? – king_nak Dec 01 '17 at 09:26

4 Answers4

2

As it became apparent a while ago, QML doesn't seem to be able to go across threads.

So one needs to implement a C++ side intermediate object that lives in the main thread to dispatch calls to objects in other threads.

QML object -> object in a different thread // doesn't work!!!
QML object -> C++ mediator object -> object in a different thread // WORKS!!!

Basically, "transcending" threads must happen in C++ entirely, thus the need of a mediator object.

dtech
  • 47,916
  • 17
  • 112
  • 190
0

I guess the someMethod will be executed in ThreadA since the object lives in that thread.

But normally if this gives a problem, then I would do something like this.

connect(&threadA, SIGNAL(started()), someObj, SLOT(someMethod());

But to start that ThreadA we need one more CppObject to link QML and CPP.

RajaRaviVarma
  • 2,502
  • 25
  • 26
  • You're right that setting up signals and slots for the object would work. This can be inconvenient with a ton of slots though, so I wanted to know the specifics of what calling the method from QML actually does. – Prismatic Aug 21 '12 at 12:33
  • Yes actually that is what I feel too. Connecting too many Signals and slots gives a mild confusion. Will check the above scenario and will report if it works fine. – RajaRaviVarma Aug 22 '12 at 10:23
0

You can use this->thread(); or QThread::currentThreadId(); inside the slot to get the thread the slot is working in. It will always be the thread, the ObjectA was created in (if there was no moveToThread()).

The Qt-Engine will select the right Qt:ConnectionType by determine call and called thread.

Extra tip: You can use GammaRay or ThreadSanitizer to see current direct connections across threads.

Louis Kröger
  • 344
  • 3
  • 10
-1

QML logic is event-driven and all invokes are parts of JavaScript functions. JS functions may be event handlers (for ex. UI event handlers) or may be invoked somewhere in C++ code if you wrap them in QScript object. Also you can invoke them in JavaScript WorkerTherad. That is why only you can provide an answer, where does someObj.someMethod() invokation take place.

Pavel Osipov
  • 2,067
  • 1
  • 19
  • 27
  • I think you misunderstood me. I'm passing a QObject to the QML Engine. By default, if the QObject has any methods marked as Q_INVOKABLE or any slots, you can call these from a qml file directly. The QML engine uses invokeMethod() to execute the method. Whether it does this using a connection type of Queued or Direct is what I was hoping to find out. What's being invoked isn't a JS function; its the C++ function. – Prismatic Aug 21 '12 at 12:32
  • 2
    I'm sure it not a good idea to make any architecture decisions, which depend on nondocumented implementation details of the framework. Make appropriate connection type by your self. – Pavel Osipov Aug 22 '12 at 07:56
  • There is no such thing as a `WorkerTherad` or even a `WorkerThread` for that matter, there is `WorkerScript` which is severely limited in terms of what it can access and be used for. – dtech Jan 26 '18 at 15:13