Безопасно ли излучать сигнал из другого потока? - PullRequest
0 голосов
/ 07 сентября 2018

Безопасно ли излучать сигнал на объект из другого потока (если слот подключен как 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();
}

1 Ответ

0 голосов
/ 07 сентября 2018

Qt основано на очередях событий. Каждый поток Qt имеет свою очередь и связанный с ней цикл обработки событий. Таким образом, когда у вас есть ситуация, когда два разных объекта живут, это два разных потока, и один из них связан с другим через механизм сигналов / слотов (либо через автоматическое, либо через очередь), во время передачи происходит следующее: код внутри сигнала создает событие и отправляет его в очередь объекта-получателя. Цикл событий получателя проходит через очередь, находит опубликованное событие и выполняет соответствующий слот.

Очередь гарантированно безопасна для потоков, поэтому абсолютно безопасно излучать сигналы между потоками. Цитата в ваших вопросах говорит о ситуации, когда вы делаете прямой вызов на объекте, живущем в T1 от T2.

Существует замечательная статья о потоках, объектах, сигналах, слотах и ​​о том, как все связано друг с другом: События потоков QObjects . Я рекомендую прочитать это, если вы хотите понять это глубже.


Относительно рассматриваемого кода. У вас есть соединение в очереди, и это означает, что не имеет значения, живут ли отправитель и получатель в одном потоке или в разных. Не имеет значения, являются ли отправитель и получатель двумя объектами или одинаковыми. Упомянутая рутина будет такой же. Если вы создали автоматическое соединение, то оно будет иметь прямой вызов, но вы этого не сделали. И соответствующую цитату из документации :

С другой стороны, вы можете безопасно излучать сигналы от вашего Реализация QThread :: run (), , потому что излучение сигнала потокобезопасно .

...