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

问题描述 投票:2回答:1

从另一个线程(如果插槽连接为QueuedConnection)在对象上发出信号是否安全?我找不到提到这个的具体文件,我找到的最多的relevant quote是这样的:

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

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

#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();
}
c++ multithreading qt thread-safety qt-signals
1个回答
1
投票

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

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

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


关于有问题的代码。您有一个排队连接,这意味着发送方和接收方是否位于一个线程或不同线程中并不重要。发送方和接收方是2个对象还是相同无关紧要。上述例程将是相同的。如果您创建了自动连接,那么它将具有直接呼叫,但您没有。以及来自documentation的相关报价:

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

© www.soinside.com 2019 - 2024. All rights reserved.