繁体   English   中英

从另一个线程发出信号是否安全?

[英]Is it safe to emit signal from another thread?

从另一个线程(如果插槽连接为QueuedConnection )在对象上发出信号是否安全? 我找不到会提到这一点的特定文档,我找到的最相关的引用是这样的:

QObject 是可重入的。 它的大多数非 GUI 子类,例如 QTimer、QTcpSocket、QUdpSocket 和 QProcess,也是可重入的,从而可以同时从多个线程使用这些类。 请注意,这些类旨在从单个线程中创建和使用; 在一个线程中创建一个对象并从另一个线程调用它的函数不能保证工作

这表明它可能不行,这也适用于信号吗? QMetaObject::activate有一个QMutexLocker ,所以在我看来它可能是线程安全的......?

#include <QCoreApplication>
#include <QTimer>
#include <thread>
#include <iostream>

struct Foo : public QObject
{
    Q_OBJECT
public:
    Foo(QObject* parent) : QObject(parent) {}

public slots:
    void run()
    {
        connect(this, &Foo::signal, this, [] { std::cout << "activated"; }, Qt::QueuedConnection);

        std::thread t([this] { emit signal(); });
        if (t.joinable()) t.join();
    }

signals:
    void signal() const;
};

#include "main.moc"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Foo* b = new Foo(&a);
    QTimer::singleShot(0, b, &Foo::run);
    return a.exec();
}

Qt 基于事件队列。 每个 Qt 线程都有自己的队列和相关的事件循环。 因此,当您遇到 2 个不同的对象存在 2 个不同的线程并且一个通过信号/插槽机制(通过自动或队列连接)连接到另一个的情况时,在发射期间会发生以下情况:信号内的代码创建一个事件并将其发布到对象接收者的队列中。 接收者的事件循环在队列中运行,找到发布的事件并执行适当的槽。

队列保证是线程安全的,因此跨线程发出信号是绝对安全的。 您问题中的引用谈到了您从T2直接调用T1的对象的情况。

有一篇关于线程、qobjects、信号、槽以及一切如何相互关联的好文章: Threads Events QObjects 如果您想更深入地了解它,我建议您阅读它。


关于有问题的代码。 你有一个排队的连接,这意味着发送者和接收者是否生活在一个线程或不同的线程中并不重要。 发送者和接收者是 2 个对象还是相同的对象并不重要。 所述例程将是相同的。 如果您创建了自动连接,那么它将有一个直接呼叫,但您没有。 以及文档中的相关引用:

另一方面,您可以安全地从 QThread::run() 实现中发射信号,因为信号发射是线程安全的

是的,这是首选方式,因为 qt GUI 阻止直接从另一个线程更改线程,因此您应该从线程之一发出信号并将其连接(接收)在线程拖曳中,并且取决于信号类型,如果您执行某些线程代码尝试直接执行代码你会得到这个错误

QObject::setParent:无法设置父级,新父级在不同的线程中

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM