首页 > 解决方案 > Invoke Qt slot safe from non-qt thread

问题描述

I want to invoke a slot of 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*/
};

But because in my case boost::asio use, with threads I don't want to have to do anything with Qt, I want to invoke this slot from a thread different from the main thread but a random thread I don't control. (On of the threads I let run boost::asio of course)

How can I do this? QCoreApplication::postEvent seems to be a nice choice, but the docs don't point out a nice way, on how to create the necessary QEvent. QMetaObject::invokeMethod with Qt::QueuedConnection seems nice too, but isn't documented as thread safe.

So how can I safely invoke a qt slot from a non qt managed thread?

(Although the title of Boost asio with Qt suggests this could be a duplicate, the question seems completely different to me, this questions is not necessarily connected to boost::asio)

标签: c++qtqt4signals-slotsqt4.8

解决方案


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

  1. Qt::QueuedConnection
  2. 由 Qt 管理的接收者的生命周期(或 AFAIK 至少直到完成调用之后)
  3. 除此以外,来自非主 qt 线程的收件人没有其他操作
  4. Qt 管理的参数的生命周期(使用 Q_ARS 或按值调用时应该没问题)

尚未记录。但是我已经创建了一个错误报告qt 论坛讨论,似乎它是有意的,并且已经创建了一个文档更改票。

我最后用的是通用模式

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

推荐阅读