Szukaj…


Używanie Qt: DirectConnection, gdy obiekt odbiornika nie odbiera sygnału

Czasami widzisz, że sygnał jest emitowany w wątku nadawcy, ale podłączony slot nie jest wywoływany (innymi słowy, nie odbiera sygnału), zapytałeś o to i ostatecznie uzyskałeś, że typ połączenia Qt :: DirectConnection to naprawi, więc problem został znaleziony i wszystko jest w porządku.

Ale generalnie jest to zły pomysł, aby używać Qt: DirectConnection, dopóki naprawdę nie wiesz, co to jest i nie ma innej drogi. Wyjaśnijmy to bardziej: Każdy wątek utworzony przez Qt (w tym wątek główny i nowe wątki utworzone przez QThread) ma pętlę zdarzeń, pętla zdarzeń odpowiada za odbieranie sygnałów i wywołuje odpowiednie szczeliny w swoim wątku. Zasadniczo wykonywanie operacji blokowania wewnątrz gniazda jest złą praktyką, ponieważ blokuje pętlę zdarzeń tego wątku, aby żadne inne gniazda nie były wywoływane.

Jeśli zablokujesz pętlę zdarzeń (wykonując bardzo czasochłonną lub blokującą operację), nie będziesz otrzymywać zdarzeń w tym wątku, dopóki pętla zdarzeń nie zostanie odblokowana. Jeśli operacja blokowania zablokuje pętlę zdarzeń na zawsze (np. Zajęty podczas), szczeliny nigdy nie zostaną wywołane.

W tej sytuacji możesz ustawić typ połączenia w połączeniu z Qt :: DirectConnection, teraz gniazda będą wywoływane, nawet jeśli pętla zdarzeń jest zablokowana. więc jak to może wszystko zepsuć? W Qt :: DirectConnection Sloty będą wywoływane w wątkach emiterów, a nie w wątkach odbiorczych i mogą przerwać synchronizację danych i napotkać inne problemy. Nigdy nie używaj Qt :: DirectConnection, chyba że wiesz, co robisz. Jeśli Twój problem zostanie rozwiązany za pomocą Qt :: DirectConnection, musisz uważnie spojrzeć na kod i dowiedzieć się, dlaczego twoja pętla zdarzeń jest zablokowana. Nie jest dobrym pomysłem blokowanie pętli zdarzeń i nie jest zalecane w Qt.

Oto mały przykład, który pokazuje problem, ponieważ widać, że nonBlockingSlot byłby wywoływany nawet w pętli zdarzeń zablokowanych blockingSlot z while (1), co wskazuje na złe kodowanie

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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow