C++ 从非Qt线程安全调用Qt插槽

C++ 从非Qt线程安全调用Qt插槽,c++,qt,qt4,signals-slots,qt4.8,C++,Qt,Qt4,Signals Slots,Qt4.8,我想调用MyWidget class MyWidget : public QWidget { Q_OBJECT public slots: void onFooBar(const std::string&);/*std::string& could also be replaced by a QString for easier meta system handling*/ }; 但是因为在我的例子中,对于我不想对Qt做任何事情的线程,我想从一个与主线程不同但我不控制

我想调用
MyWidget

class MyWidget : public QWidget {
Q_OBJECT

public slots:
void onFooBar(const std::string&);/*std::string& could also be replaced
    by a QString for easier meta system handling*/
};
但是因为在我的例子中,对于我不想对Qt做任何事情的线程,我想从一个与主线程不同但我不控制的随机线程调用这个插槽。(当然是在我允许运行的线程中的一个线程上)


我该怎么做
QCoreApplication::postEvent
似乎是一个不错的选择,但文档没有指出如何创建必要的
QEvent
QMetaObject::invokeMethod
Qt::QueuedConnection
看起来也不错,但没有作为线程安全的文档记录

那么如何从非qt托管线程安全地调用qt插槽呢?


(虽然标题表明这可能是一个重复的问题,但我觉得这个问题完全不同,这个问题不一定与
boost::asio
)有关。)

结果是
QMetaObject::invokeMethod
Qt::QueuedConnection
在其实现中实际使用了
QCoreApplication::postEvent
(谢谢@peppe!)。但是,当

  • 与Qt::QueuedConnection一起使用
  • Qt管理的收件人的生存期(或至少在完成调用之前的AFAIK)
  • 除了从非主qt线程执行类似操作之外,对收件人没有其他操作
  • Qt管理的参数的生存期(在使用Q_ARS或按值调用时应该可以)
  • 还没有记录在案。但我已经创建了一个和讨论,它似乎是有意这样做的,并且已经创建了一个

    我最后使用的是通用模式

    class MyWidget : public QWidget {
    Q_OBJECT
    
    public slots:
    void onFooBar(QString);
    };
    
    void asio_handler(const std::string& string, MyWidget* my_widget) {
    QMetaObject::invokeMethod(
                            my_widget, "onFooBar", Qt::QueuedConnection,
                            Q_ARG(QString, QString::fromStdString(string))
                            );
    }
    

    我只记得我曾经做过类似的事情(不知何故):。可能是,今天我会使用发布的事件而不是
    QTimer
    。@Scheff使用
    QMetaObject::invokeMethod
    的解决方案似乎是常见的模式,但是与
    QCoreApplication::postEvent
    相比,没有关于线程安全的文档。为此,我已经创建了一个bug报告,解决了这个问题后,我会用这个解决方案自我回答这个问题
    QMetaObject::invokeMethod
    通过发布事件来实现排队连接(参见示例)。如果您查看代码,它与
    postEvent
    一样是线程安全的。我不完全确定为什么没有这样的文档记录;可能是为了避免混淆线程安全指的是什么,特别是在涉及直接连接的情况下(“目标”对象不包含在安全承诺中!),添加了文档的相关部分。请注意。1)
    invokeMethod
    始终是线程安全的。但是,安全性与
    invokeMethod
    本身内部的逻辑有关,而与目标对象无关。例如,从不同线程对同一对象的直接调用将要求目标对象本身是线程安全的。2)目标的生存期可以根据需要进行管理,不一定使用Qt工具。重要的一点是,在调用
    invokeMethod
    期间,目标是活动的。(理论上,它可以在之后立即删除。对于排队连接,这可能意味着不调用目标方法。)3)不正确--
    invokeMethod
    本身是线程安全的!例如,您可以安全地在同一目标对象上同时从多个线程调度对给定函数的排队调用,而无需任何手动同步。(然后将从目标对象的关联线程进行调用。)您甚至可以同时从多个线程对同一目标对象进行多个直接调用,而无需同步,但这同样要求目标对象是线程安全的。4)当您进行排队调用时,函数参数在幕后发布的事件中复制,因此当
    invokeMethod
    返回时,您可以安全地删除它们。(这就是为什么需要为参数类型调用
    qRegisterMetaType
    ,这反过来又要求这些类型是可复制的。这将复制事件对象中的函数参数。)