不能在另外的线程直接delete一个QObject对象,相反,你需要调用QObject::deleteLater()函数,这个函数会给对象所在线程发送一个删除的事件。
QObject的线程依附性是可以改变的,方法是调用QObject::moveToThread()函数。该函数会改变一个对象及其所有子对象的线程依附性。
由于QObject不是线程安全的,所以我们只能在该对象所在线程上调用这个函数。也就是说,我们只能在对象所在线程将这个对象移动到另外的线程,不能在另外的线程改变对象的线程依附性。
还有一点是,Qt 要求QObject的所有子对象都必须和其父对象在同一线程。这意味着:
参考:QT 学习之路 2(74):线程和 QOBJECT
class Test : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE void show(int i) {
qDebug()<<"show "<
需要用Q_INVOKABLE声明,invokeMethod才能调用,否则会找不到show这个接口。
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
auto t = new Test;
auto thread = new QThread;
thread->start();
int i = 0;
qDebug()<<"main thread: "<show(i++); // 0
QMetaObject::invokeMethod(t, "show", Qt::DirectConnection, Q_ARG(int, i++)); // 1
connect(this, &MainWindow::test, t, &Test::show);
emit test(i++); // 2
disconnect(this, &MainWindow::test, t, &Test::show);
t->moveToThread(thread);
qDebug()<<"after move to thread: "<show(i++); // 3
QMetaObject::invokeMethod(t, "show", Qt::DirectConnection, Q_ARG(int, i++)); // 4
QMetaObject::invokeMethod(t, "show", Qt::QueuedConnection, Q_ARG(int, i++)); // 5
connect(this, &MainWindow::test, t, &Test::show, Qt::DirectConnection);
emit test(i++); // 6
disconnect(this, &MainWindow::test, t, &Test::show);
connect(this, &MainWindow::test, t, &Test::show);
emit test(i++); // 7
disconnect(this, &MainWindow::test, t, &Test::show);
}
只有在线程启动后,并且通过信号槽和invokeMethod调用,且是队列的方式,才能让QOject子对象的show函数跑在子线程中。
并非是将a实例相关的所有的工作“移动”到了m_thread线程,而是将所有a实例相关的事件托管到m_thread线程执行。换句话说,就是通过信号槽connect或者invokeMethod触发a实例中槽函数产生的事件,将会被放置到m_thread线程中执行。
参考:[moveToThread实现多线程操作的理解(https://blog.csdn.net/yzt629/article/details/105429367)
Q_INVOKABLE与invokeMethod用法全解