Suche…


Verwendung von Qt: DirectConnection, wenn das Empfängerobjekt kein Signal empfängt

Wenn Sie sehen, dass im Sender-Thread ein Signal ausgegeben wird, der verbundene Slot jedoch nicht aufgerufen wird (dh, er empfängt kein Signal), haben Sie danach gefragt und haben schließlich festgestellt, dass der Verbindungstyp Qt :: DirectConnection das Problem beheben würde. also das problem gefunden und alles ist ok.

Im Allgemeinen ist dies jedoch keine gute Idee, Qt: DirectConnection zu verwenden, bis Sie wirklich wissen, was das ist, und es gibt keinen anderen Weg. Erklären wir es näher. Jeder von Qt erstellte Thread (einschließlich des Haupt-Threads und neuer von QThread erstellter Threads) verfügt über eine Ereignisschleife. Die Ereignisschleife ist für den Empfang von Signalen verantwortlich und ruft entsprechende Slots in ihrem Thread auf. Das Ausführen einer Blockierungsoperation in einem Slot ist generell eine schlechte Praxis, da die Ereignisschleife dieser Threads blockiert wird, sodass keine anderen Slots aufgerufen werden.

Wenn Sie eine Ereignisschleife blockieren (indem Sie einen sehr zeitaufwändigen oder blockierenden Vorgang durchführen), erhalten Sie keine Ereignisse in diesem Thread, bis die Ereignisschleife freigegeben wird. Wenn der Blockierungsvorgang die Ereignisschleife für immer blockiert (z. B. beschäftigt, während), können die Slots niemals aufgerufen werden.

In dieser Situation können Sie den Verbindungstyp in Verbindung mit Qt :: DirectConnection festlegen. Jetzt werden die Steckplätze aufgerufen, auch wenn die Ereignisschleife blockiert ist. wie konnte das also alles kaputt machen? In Qt :: DirectConnection werden Slots in Emiterthreads und nicht in Empfängerthreads aufgerufen. Dadurch können Datensynchronisierungen unterbrochen werden und andere Probleme auftreten. Verwenden Sie daher niemals Qt :: DirectConnection, es sei denn, Sie wissen, was Sie tun. Wenn Ihr Problem durch die Verwendung von Qt :: DirectConnection gelöst wird, müssen Sie Ihren Code genau prüfen und herausfinden, warum Ihre Ereignisschleife blockiert ist. Es ist keine gute Idee, die Ereignisschleife zu blockieren und in Qt nicht zu empfehlen.

Hier ist ein kleines Beispiel, das das Problem zeigt. Wie Sie sehen können, würde der nonBlockingSlot auch die geblockte EventSchleife mit while (1) heißen, was auf eine schlechte Codierung hinweist

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();
}


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow