簡體   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