В ObjC с GCD существует способ выполнения лямбда в любом из потоков, которые вращают цикл событий. Например:
dispatch_sync(dispatch_get_main_queue(), ^{ /* do sth */ });
или
dispatch_async(dispatch_get_main_queue(), ^{ /* do sth */ });
Он выполняет что-то (эквивалентное []{ /* do sth */ }
в С++) в очереди основного потока, либо блокируя, либо асинхронно.
Как я могу сделать то же самое в Qt?
Из того, что я прочитал, я думаю, что решение было бы каким-то образом отправить сигнал на какой-то объект основного потока. Но какой объект? Просто QApplication::instance()
? (Это единственный объект, живущий в основном потоке в этой точке.) И какой сигнал?
Из текущих ответов и моих текущих исследований действительно кажется, что мне нужен какой-то фиктивный объект для сидения в основном потоке с некоторым слотом, который просто ждет, чтобы попасть в какой-то код для выполнения.
Итак, я решил подклассом QApplication
добавить это. Мой текущий код, который не работает (но, возможно, вы можете помочь):
#include <QApplication>
#include <QThread>
#include <QMetaMethod>
#include <functional>
#include <assert.h>
class App : public QApplication
{
Q_OBJECT
public:
App();
signals:
public slots:
void genericExec(std::function<void(void)> func) {
func();
}
private:
// cache this
QMetaMethod genericExec_method;
public:
void invokeGenericExec(std::function<void(void)> func, Qt::ConnectionType connType) {
if(!genericExec_method) {
QByteArray normalizedSignature = QMetaObject::normalizedSignature("genericExec(std::function<void(void)>)");
int methodIndex = this->metaObject()->indexOfSlot(normalizedSignature);
assert(methodIndex >= 0);
genericExec_method = this->metaObject()->method(methodIndex);
}
genericExec_method.invoke(this, connType, Q_ARG(std::function<void(void)>, func));
}
};
static inline
void execInMainThread_sync(std::function<void(void)> func) {
if(qApp->thread() == QThread::currentThread())
func();
else {
((App*) qApp)->invokeGenericExec(func, Qt::BlockingQueuedConnection);
}
}
static inline
void execInMainThread_async(std::function<void(void)> func) {
((App*) qApp)->invokeGenericExec(func, Qt::QueuedConnection);
}