[英]Is it possible to force execute main thread (GUI thread) from render thread?
我们有在渲染线程中执行的命令队列,直接在QQuickWindow::beforeRendering
和QQuickWindow::afterRendering
,命令对数据模型进行更改,当数据模型更改时,它立即通知我们的自定义 OpenGL 渲染引擎同步数据。
问题是当数据模型更改时,它也会通知旨在更新 UI 的订阅者。 但是从不同的线程更新 UI 是一种容易出错的方法。 一种方法是使用Qt::QueuedConnection
。 这也很容易出错,因为执行时模型可能会进入远态。
设计与这个例子非常相似。
例如,是否可以从渲染线程更新与 QML 链接的QStadardItemModel
?
有可能,您可以使用QMetaObject::invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr)
的QMetaObject::invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr)
重载来QMetaObject::invokeMethod
。
对于上下文,您需要传递一个生活在要运行函数的线程上的对象。 对于 GUI 线程, QCoreApplication::instance()
是一个不错的选择。 对于连接类型,根据您的需要使用Qt::QueueConnection
或Qt::BlockingQueuedConnection
(您是否需要调用阻塞)。 如果您正在使用Qt::BlockingQueuedConnection
,请确保您当前不在主线程中(如果是这种情况,您可以进行检查并通过Qt::DirectConnection
)。
而对于函子来说,一个 lambda 就可以解决问题。
例如:
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();
这输出:
1 main thread 0x1c7c
2 main thread 0x1c7c
1 QtConcurrent thread 0x19ec
invokeMethod thread 0x1c7c
2 QtConcurrent thread 0x19ec
您可以从Calling Qt Functions From Unix Signal Handlers 中获得灵感
您可能有一些中央数据结构,例如一些包含lambda 表达式的std::deque
; 让我们称之为您的待办事项清单。 该待办事项列表还管理一个管道(7) (所以两个文件描述符)。
您将使用适当的std::mutex
保护该待办事项列表并使用std::condition_variable
您将通过使用一些pipe(7)或fifo(7)在渲染线程和主 Qt 线程之间进行同步,然后使用(在主线程中)一些QSocketNotifier进行同步。 在向您的 todolist 添加闭包时,渲染线程还会向该 fifo 或管道写入(2)一些字节,并且主线程将使用QSocketNotifier
读取(2)它,然后从您的 todo 列表中获取(弹出)一个闭包并运行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.