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

Is it safe to emit signal from another thread?

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

QObject is reentrant. Most of its non-GUI subclasses, such as QTimer, QTcpSocket, QUdpSocket and QProcess, are also reentrant, making it possible to use these classes from multiple threads simultaneously. Note that these classes are designed to be created and used from within a single thread; creating an object in one thread and calling its functions from another thread is not guaranteed to work.

这表明它可能不正常,这也适用于信号吗? 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 个不同的线程中生活并且一个通过 signals/slots 机制(通过自动或排队连接)连接到另一个的情况时,在发射期间会发生以下情况:信号中的代码创建一个事件并将其发布到对象接收者的队列中。接收者的事件循环是 运行 通过队列,找到发布的事件并执行适当的插槽。

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

对生活在 T1 中的对象进行 直接调用 的情况

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


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

On the other hand, you can safely emit signals from your QThread::run() implementation, because signal emission is thread-safe.

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

QObject::setParent: Cannot set parent, new parent is in a different thread