直接进入主题,据我所知,方法有3种:
1、自定义signal、slot,这个就不多说了,标准方法
2、使用QmetaMethod::invoke,这是可以直接在子线程调用的,看起来比较另类
3、从5.4开始,有了另一种新方法:Qtimer::singleShot(0),这玩意儿可不是定时启动那么简单,你给他0的时间他就是GUI线程安全的,完整例子可以测试:
#include <QCoreApplication>#include <QTimer> #include <QDebug> #include <thread> #include <QThread> #include <QEventLoop> #include <QThread> using std::thread; class TestObj :public QObject { // Used new connect syntax no need for Q_OBJECT define // you SHOULD use it. I used just to upload one file //Q_OBJECT public slots: void doWork() { qDebug() << "QThread id" << QThread::currentThreadId(); QTimer::singleShot(0, qApp, []() { qDebug() << "singleShot from QThread" << QThread::currentThreadId(); }); } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << "main thread id" << QThread::currentThreadId(); thread testThread([]() { QEventLoop loop; Q_UNUSED(loop) qDebug() << "std::thread id" << QThread::currentThreadId(); QTimer::singleShot(0, qApp, []() { qDebug() << "singleShot from std thread with qApp" << QThread::currentThreadId(); }); qDebug() << "std::thread finished"; }); testThread.detach(); QThread testQThread; TestObj testObj; testObj.moveToThread(&testQThread); QObject::connect(&testQThread, &QThread::started, &testObj, &TestObj::doWork); testQThread.start(); // 下列方法2选1,都可以退出app //QMetaObject::invokeMethod(&a, "quit", Qt::QueuedConnection); QTimer::singleShot(0, &a, [&a]() { a.quit(); }); // 直接调用a.quit();是无法退出的,因为没有到eventloop // a.quit(); a.exec(); testQThread.quit(); testQThread.wait(); return 0; }
输出:
main thread id 0x1bb4 std::thread id 0x294c std::thread finished QThread id 0x1bd4 singleShot from std thread with qApp 0x1bb4 singleShot from QThread 0x1bb4
可以看到,qtimer执行的一直是主线程,也就是GUI线程。