从 non-qt 线程调用 Qt 槽安全

Invoke Qt slot safe from non-qt thread

我想调用 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*/
};

但是因为在我的例子中 boost::asio 使用线程,我不想对 Qt 做任何事情,我想从一个不同于主线程的线程调用这个槽,而是一个随机线程我不控制。 (当然,在我让 运行 boost::asio 的线程中)

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

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

(虽然 Boost asio with Qt 的标题表明这可能是重复的,但这个问题对我来说似乎完全不同,这个问题不一定与 boost::asio 相关)

原来 QMetaObject::invokeMethodQt::QueuedConnection 实际上在其实现中使用了 QCoreApplication::postEvent(感谢@peppe!)。但是保证它是线程安全的,当

  1. Qt::QueuedConnection
  2. 一起使用
  3. 由 Qt 管理的收件人的生命周期(或 AFAIK 至少在完成调用之前)
  4. 除了像这样来自非主 qt 线程之外,收件人没有其他操作
  5. 由 Qt 管理的参数的生命周期(使用 Q_ARS 或按值调用时应该没问题)

尚未记录。但是我已经创建了bug report and qt forum discussion, and it seems it was intended to be so, and a documentation change ticket 已经创建了

我最后用的是普通模式

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))
                        );
}