Qt Utilisation de Qt: DirectConnection lorsqu'un objet récepteur ne reçoit pas de signal


Exemple

Parfois, vous voyez qu'un signal est émis dans le thread émetteur, mais le connecteur connecté ne l'appelle pas (en d'autres termes, il ne reçoit pas de signal), vous avez demandé à ce sujet le type de connexion Qt :: DirectConnection donc le problème trouvé et tout va bien.

Mais en règle générale, il est déconseillé d’utiliser Qt: DirectConnection jusqu’à ce que vous sachiez vraiment ce que c’est et qu’il n’ya pas d’autre moyen. Expliquons-le davantage. Chaque thread créé par Qt (y compris le thread principal et les nouveaux threads créés par QThread) possède une boucle d'événement, la boucle d'événement est chargée de recevoir les signaux et appelle des emplacements appropriés dans son thread. Généralement, l'exécution d'une opération de blocage dans un logement est une mauvaise pratique, car elle bloque la boucle d'événement de ces threads afin qu'aucun autre emplacement ne soit appelé.

Si vous bloquez une boucle d'événement (en prenant beaucoup de temps ou en bloquant l'opération), vous ne recevrez pas d'événements sur ce thread tant que la boucle d'événement ne sera pas débloquée. Si l'opération de blocage bloque la boucle d'événement pour toujours (comme un temps occupé), les emplacements ne pourront jamais être appelés.

Dans cette situation, vous pouvez définir le type de connexion dans la connexion à Qt :: DirectConnection, maintenant les emplacements seront appelés même la boucle d'événement est bloquée. alors comment cela pourrait faire tout casser? Dans Qt :: DirectConnection, les slots seront appelés dans les threads émetteurs, et non dans les threads récepteurs, et ils pourront briser les synchronisations de données et rencontrer d’autres problèmes. N'utilisez donc jamais Qt :: DirectConnection à moins de savoir ce que vous faites. Si votre problème est résolu à l'aide de Qt :: DirectConnection, vous devez examiner votre code et déterminer pourquoi votre boucle d'événements est bloquée. Ce n'est pas une bonne idée de bloquer la boucle d'événement et ce n'est pas recommandé dans Qt.

Voici un petit exemple qui montre le problème, car vous pouvez voir que le nonBlockingSlot serait appelé même la boucle d'événement bloqué blockingSlot avec while (1), ce qui indique un mauvais codage

class TestReceiver : public QObject{
    Q_OBJECT
public:
    TestReceiver(){
         qDebug() << "TestReceiver Constructed in" << QThread::currentThreadId();
    }
public slots:
    void blockingSlot()
    {
        static bool firstInstance = false;
        qDebug() << "Blocking slot called in thread" << QThread::currentThreadId();
        if(!firstInstance){
            firstInstance = true;
            while(1);
        }
    }
    void nonBlockingSlot(){
        qDebug() << "Non-blocking slot called" << QThread::currentThreadId();
    }
};

class TestSender : public QObject{
    Q_OBJECT
public:
    TestSender(TestReceiver * receiver){
        this->nonBlockingTimer.setInterval(100);
        this->blockingTimer.setInterval(100);

        connect(&this->blockingTimer, &QTimer::timeout, receiver, &TestReceiver::blockingSlot);
        connect(&this->nonBlockingTimer, &QTimer::timeout, receiver, &TestReceiver::nonBlockingSlot, Qt::DirectConnection);
        this->nonBlockingTimer.start();
        this->blockingTimer.start();
    }
private:
    QTimer nonBlockingTimer;
    QTimer blockingTimer;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    TestReceiver TestReceiverInstance;
    TestSender testSenderInstance(&TestReceiverInstance);
    QThread receiverThread;
    TestReceiverInstance.moveToThread(&receiverThread);
    receiverThread.start();

    return a.exec();
}