Reputation: 43
We have commands queue which executed in render thread, directly between QQuickWindow::beforeRendering
and QQuickWindow::afterRendering
, commands do changes on data model, and when data model changes it immediately notify our custom OpenGL render engine to sync data.
The problem is when data model changes it also notify subscribers who aim to update UI.
But it is error prone approach to update UI from different thread. One way is using Qt::QueuedConnection
. This is error prone too because when it come executed model may go to far state.
Design is very similar to this example.
Is it possible for example update QStadardItemModel
linked with QML from render thread?
Upvotes: 2
Views: 1423
Reputation: 1
You could get inspiration from Calling Qt Functions From Unix Signal Handlers
You might have some central data structure, e.g. some std::deque
containing lambda expressions; let's call it your todo list. That todo list also manages a pipe(7) (so two file descriptors).
You would protect that todo list with appropriate std::mutex
and use std::condition_variable
You would synchronize between the render thread and the main Qt thread by using some pipe(7) or fifo(7), then use (in the main thread) some
QSocketNotifier for synchronization. The render thread would also write(2) some byte to that fifo or pipe when adding a closure to your todolist, and the main thread would use QSocketNotifier
to read(2) it, then fetch (pop) a closure from your todo list and run it.
Upvotes: 2
Reputation: 7160
It is possible, you can do it with the QMetaObject::invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr)
overload of QMetaObject::invokeMethod
.
For the context you need to pass an object living on thread you want to run your function. For the GUI thread, QCoreApplication::instance()
is a good candidate.
For the connection type, use Qt::QueueConnection
or Qt::BlockingQueuedConnection
depending on your needs (weither you need the call to block or not). If you are using Qt::BlockingQueuedConnection
, make sure that you are not currently in the main thread (you could do a check and pass Qt::DirectConnection
if that is the case).
And for the functor, a lambda will do the trick.
In example :
qDebug() << "1 main thread" << QThread::currentThreadId();
QtConcurrent::run([] {
qDebug() << "1 QtConcurrent thread" << QThread::currentThreadId();
QMetaObject::invokeMethod(QCoreApplication::instance(), [] {
qDebug() << "invokeMethod thread" << QThread::currentThreadId();
}, Qt::BlockingQueuedConnection);
qDebug() << "2 QtConcurrent thread" << QThread::currentThreadId();
});
qDebug() << "2 main thread" << QThread::currentThreadId();
This outputs:
1 main thread 0x1c7c
2 main thread 0x1c7c
1 QtConcurrent thread 0x19ec
invokeMethod thread 0x1c7c
2 QtConcurrent thread 0x19ec
Upvotes: 3