QML: threading model for WorkerScript - qt

When using a QML WorkerScript, are the requests (sent via postMessage()) queued (and executed on a single handler thread) or is there the possibility/danger that two successive postMessage() will be executed on two threads concurrently?

Short answer
All WorkerScript should execute in the same thread.
Not so short answer
All WorkerScript in a QQmlEngine should execute in the same thread.
Long answer
When you create a WorkerScript in QML you instantiate the QQuickWorkerScript C++ class. This class uses the QQuickWorkerScriptEngine class to handles all the thready things.
Now, if you look at QQuickWorkerScript::engine() and QQmlEnginePrivate::getWorkerScriptEngine() you will see that all WorkerScript objects will share the same QQuickWorkerScriptEngine instance as long as they share the same QQmlEngine.
Also QQuickWorkerScriptEngine is a QThread (public inheritance) and contains a member variable named d of type QQuickWorkerScriptEnginePrivate *. d is running in the thread handled by QQuickWorkerScriptEngine (see d->moveToThread(this) in QQuickWorkerScriptEngine constructor). And it is this d that will effectively run the asynchronous work in QQuickWorkerScriptEnginePrivate::event().
PS
This kind of contradicts Qt documentation that states:
Use WorkerScript to run operations in a new thread.
Which might make you think that each WorkerScript is a new thread.

Related

QObject deleteLater after QThread quit

I want to design a single base class for both controlling the thread and executing slots of the class in thread itself via qobject::connect or invokemethod.
When start is called, I call this->movetothread(memthread) and memthread->start to move this into member thread's context and start the eventloop.
when stop is called, qthread's quit is called to stop the event loop. Problem is that, when thread quits, it is impossible to deallocate "this" via deletelater later on since deletelater needs a running eventloop to delete the object. Object's thread context could already be stopped via call to quit before.
I can't connect object->deletelater to thread::finished since object would be unusuable then and I can't start/stop thread again. My aim in the design is to accomplish this actually. Being able to stop the thread, start later, stop again and so on.
I'm not sure if the design is doable with the way qt is but want to at least try.
P.S. My first question, please kindly let me know about any mistakes.
I am not sure I understand the question completely, and also there are very few details. However, why stopping the thread in the first place? Anyway, depending on the specific context, you could start the thread when you want to delete your object and then delete it, then stop the thread and delete the QThread. Otherwise you could simply delete your object. Anther option is to move your object to the main thread when stopping your thread:
QMetaObject::invokeMethod(this, [this] {
moveToThread(qApp->thread());
});
and then simply deleteLater() when you feel you are ready. These are two options, but I think there are others, it depends on your context.

Passing object via Qt signal/slot across threads

I wish to pass an object using the signal/slot mechanism between threads in Qt. Since I will be passing a pointer to the object, is it safe to call the methods on the object on the receiver's side?
According to this question question the object is not copied (so using original object).
Is this safe? Or am I executing methods on an object belonging to one thread in another thread? Is there a better way to do this?
(I have approximately 20 getters in this class so I don't want to pass individual variables, as well some of the variables are in fact pointers to objects as well)
It is not necessarily safe - signals and slots can be used to cross thread boundaries, so it's possible you could end up trying to access the object from another thread.
The thread in which the slot will be called is determined by the connection type. See the documentation, but as an example:
connect(source, SIGNAL(mySignal(QObject*)), destination, SLOT(mySlot(QObject*)), Qt::DirectConnection);
In this case the function mySlot() will be called from the same thread that the mySignal() signal was emitted in. If your object is not accessed from any threads other than the same thread as the signal emitter this would work fine.
connect(source, SIGNAL(mySignal(QObject*)), destination, SLOT(mySlot(QObject*)), Qt::QueuedConnection);
In this case the function mySlot() will be queued, and called by the event loop of the destination object. So anything done to the object, would happen from within the thread running the event loop of the destination.
I personally find it's best to just stick to passing simple values as arguments. Even though this can work, you would need to add suitable multithreading guards to your QObject if it's likely to be accessed from multiple threads.
First of all, try to use QtConcurrent when you are developing a multi-threaded application. The QtConcurrent namespace provides high-level APIs that make it possible to write multi-threaded programs without using low-level threading primitives such as mutexes, read-write locks, wait conditions, or semaphores.
After that, safety depends on your class members. If all members are thread-safe, then all will be run safely.

Blocked QFuture.result() or QFutureWatcher.waitForFinished();

So I have been using QtConcurrent::run for some time and its fantastic. But now I need the function to return an object. Therefore I use the pseudo code
QFutureWatcher<MyObject> fw;
QFuture<MyObject> t1 = QtConcurrent::run(&thOb, &MythreadObjFunc::getList, ConSettings, form, query);
fw.setFuture(t1);
// Both .results() and waitForFinished() block
fw.waitForFinished();
MyObject entries = t1.result();
Then I iterate through the myObject. The issue is that this is blocking e.g. my main GUI is not responsive. And this was the whole reason I started using QtConcurrent::run
Therefore, what is the recommended way to have my GUI execute a QtConcurrent::run and get the object back but not block? I thought of signals and slots where the signal would be from the QtConcurrent::run but this would mean that it would be from a different thread and I read thats not recommended.
Thanks for your time.
You should never use any waitForFinished functions in the GUI thread. Instead, connect a slot to the future watcher's finished signal. See this answer for an example.
From QtConcurrent::run() you can't emit any signal. Runnable function is not a QObject. That is the first thing.
The other thing is that QFutureWatcher::waitForFinished() blocks the execution until the thread ends its execution. This is the intended behaviour. If you have to wait for your function to finish, why do you even launch it on separate thread? It makes no sense.
The easiest solution would be to make your function a member of QObject-inherited class, move the instance to the other thread, launch the calculations and emit done() signal. Qt's signal and slot system is thread-safe and it is the perfect way to use it. There is a outstanding documentation provided by Qt that covers this subject more than enough. You should start reading here: http://qt-project.org/doc/qt-4.8/threads.html

Running a function in different thread in QT

In Qt Application code Class A has one member method like method1(). I want to call this method in another member function method2() and run mehtod1() in a different thread. But what I found from the qt documentation is follows.
Inherit a new class MyThread(suppose) from QThread.
Override the function method run() with your required code.
Create an object of MyThread in Class A and then call the run function wherever you want.
But the above seems bit complex. Is there any mechanism in Qt so that I can create a new QThread(without inheriting) instantly in my method1() and run the method2() with this thread and then return to method1() after execution finishes?
Please let me know if I am not clear in my question.
Yes there is a way like you want.
This article will help you to understand why it's not the correct way to inherit from QThread: https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
This article will help you to know how use QThread in a real simple way: https://www.qt.io/blog/2006/12/04/threading-without-the-headache
You can use QObject slots and signals or event support, combined with threads.
Basically, a QObject's slots called through signal/slot mechanism are executed in the thread that created the QObject. You can also move the object ownership from one thread to another using QObject::moveToThread.
You can also use QCoreApplication::postEvent to post events for execution in the thread the object was created in.
See more about threads and QObjects in Qt documentation ("Threads and QObjects" topic in index).
Going to your problem, you can use two separate objects in different threads to "spread" the execution.

How can I find out when a PyQt-application is idle?

I'd like to know when my application is idle so that I can preload some content. Is there an event or something similar implemented in PyQt?
(I could also do it with threads, but this feels like being too complicated.)
You have at least two different options, you can use a thread or use a timer. Qt's QThread class provides a priority property that you can set to make it only process when no other threads are running, which includes the GUI thread. The other option is a single shot timer. A QTimer with a timeout of 0 milliseconds puts an event on the back of the event queue so that all events and synchronous functions already active or scheduled will be processed first.
In code, the two options would look like the following:
// (1) use idle thread processing
MyQThreadSubclass idleThread;
idleThread.run(QThread::IdlePriority);
// (2) use QTimer::singleShot
QTimer::singleShot(0, receiver, SLOT(doIdleProcessingChunk));
If you go with the single shot QTimer, be careful how much processing you do as you can still block the Gui. You'd likely want to break it into chunks so that GUI won't start to lag:
// slot
void doIdleProcessingChunk() {
/* ... main processing here ... */
if (chunksRemain())
QTimer::singleShot(0, receiver, SLOT(doIdleProcessingChunk));
}
Obviously, the above is C++ syntax, but to answer with respect to PyQt, use the single shot timer. In Python, the global interpreter lock is basically going to render much of your concurrency pointless if the implementation being called is performed within Python.
You also then have the choice of using Python threads or Qt threads, both are good for different reasons.
Have a look at QAbstractEventDispatcher. But ... I still suggest to use a thread. Reasons:
It will be portable
If you make a mistake in your code, the event loop will be broken -> You app might hang, exit all of a sudden, etc.
While the preloading happens, your app hangs. No events will be processed unless you can preload the content one at a time, they are all very small, loading takes only a few milliseconds, etc.
Use a thread and send a signal to the main thread when the content is ready. It's so much more simple.

Resources