为啥从线程执行方法时使用 QMetaObject::invokeMethod

Posted

技术标签:

【中文标题】为啥从线程执行方法时使用 QMetaObject::invokeMethod【英文标题】:Why using QMetaObject::invokeMethod when executing method from thread为什么从线程执行方法时使用 QMetaObject::invokeMethod 【发布时间】:2012-12-19 08:35:52 【问题描述】:

我有以下代码:

class A : public QObject

    Q_OBJECT
public:
    A() : QObject()
    
         moveToThread(&t);
         t.start();
    
    ~A()
    
         t.quit();
         t.wait();
    

    void doSomething()
     
         QMetaObject::invokeMethod(this,"doSomethingSlot");
    
public slots:
    void doSomethingSlot()
    
         //do something
         emit ready();
    
signals:
    void ready();
private:
    QThread t;

为什么来自doSomething 的问题必须通过QMetaObject::invokeMethod 调用。我知道有一些与连接类型有关的东西。 有人能解释一下幕后是什么吗?

【问题讨论】:

ecatmur 给了你完美的答案。您还有另一个问题,将线程作为移动到该线程的对象的成员是非常糟糕的主意,在销毁期间(使用 deleteLater 时)您可能会遇到奇怪的问题。 完整解释请阅读this document @MarekR:有什么问题?我从***.com/questions/13878745/… 得到了这个解决方案 delateLater 在适当的线程中调用析构函数。当您销毁它时,您还将尝试销毁线程。所以代码会让线程保持活动状态并且代码会尝试销毁线程:它会挂起。所以这个解决方案只会破坏 delateLater 的功能。 deleteLater 在哪里使用? 【参考方案1】:

由于您没有指定Qt::ConnectionType,因此该方法将被调用为Qt::AutoConnection,这意味着如果对象的线程亲和性是当前线程,它将被同步调用(就像正常的函数调用一样),否则异步。 “异步”是指构造一个QEvent并将其推送到消息队列中,并在事件循环到达时处理。

如果接收对象可能在另一个线程中,则使用QMetaObject::invokeMethod 的原因是尝试直接在另一个线程中的对象上调用插槽可能会导致损坏或更糟,如果它访问或修改非线程安全数据.

【讨论】:

你的意思是如果我从另一个线程使用 A.doSomething() 可能会导致损坏?为什么这样?你能描述一下这个机制吗? @krzych 例如,如果您在另一个线程正在修改它的同时从 QString 读取,那么它可能看起来处于不一致的状态,从而导致间接无效指针。【参考方案2】:

我喜欢这个技巧:

void A:doSomethingSlot()

     if (thread()!=QThread::currentThread()) 
         QMetaObject::invokeMethod(this,"doSomethingSlot", Qt::QueuedConnection);
         return;
     
     // this is done always in same thread
     ...
     emit ready();

【讨论】:

不要那样做,使用编译时检查:QMetaObject::invokeMethod(this, [this] doSomethingSlot(); , Qt::QueuedConnection);

以上是关于为啥从线程执行方法时使用 QMetaObject::invokeMethod的主要内容,如果未能解决你的问题,请参考以下文章

如果我从线程调用 QMetaObject::invokeMethod 到单音,调用是不是仍在该 qthread 中?

QMetaObject::invokeMethod 不调用槽

Main 方法在执行过程中等待线程完成。为啥?

如何从类名中找到 Qt 元对象实例?

为啥并行多线程代码执行比顺序慢?

如果我每次都从不同的线程调用事件,为啥会从同一个线程触发事件处理程序的多次执行?