Qt
Insidie comuni
Ricerca…
Usando Qt: DirectConnection quando l'oggetto ricevente non riceve il segnale
Alcune volte si vede un segnale emesso nella sequenza del mittente, ma lo slot collegato non viene chiamato (in altre parole non riceve il segnale), lo si è chiesto e finalmente si è capito che il tipo di connessione Qt :: DirectConnection lo avrebbe risolto, quindi il problema è stato riscontrato e tutto è a posto.
Ma in generale questa è una pessima idea usare Qt: DirectConnection fino a quando non si sa veramente cos'è questo e non c'è altro modo. Lo spieghiamo di più, Ogni thread creato da Qt (incluso il thread principale e i nuovi thread creati da QThread) ha un loop degli eventi, il loop degli eventi è responsabile della ricezione dei segnali e chiama gli slot aproporiate nella sua discussione. Generalmente l'esecuzione di un'operazione di blocco all'interno di uno slot è una cattiva pratica, perché blocca il loop degli eventi di tali thread in modo che non vengano chiamati altri slot.
Se si blocca un ciclo di eventi (effettuando un'operazione molto lunga o bloccante) non si riceveranno eventi su quel thread fino a quando il ciclo degli eventi non verrà sbloccato. Se l'operazione di blocco blocca il ciclo di eventi per sempre (come occupato mentre), gli slot non potranno mai essere chiamati.
In questa situazione è possibile impostare il tipo di connessione in connessione a Qt :: DirectConnection, ora gli slot verranno chiamati anche se il loop eventi è bloccato. quindi come questo avrebbe potuto rompere tutto? In Qt :: DirectConnection gli slot verranno chiamati nei thread degli emitter e non nei thread del ricevente e possono rompere le sincronizzazioni dei dati e incorrere in altri problemi. Quindi non usare mai Qt :: DirectConnection se non sai cosa stai facendo. Se il tuo problema verrà risolto usando Qt :: DirectConnection, dovrai fare attenzione e guardare il tuo codice e scoprire perché il tuo ciclo degli eventi è bloccato. Non è una buona idea bloccare il ciclo degli eventi e non è raccomandato in Qt.
Ecco un piccolo esempio che mostra il problema, come si può vedere il nonBlockingSlot sarebbe chiamato anche il ciclo di eventi blockingSlot bloccato con while (1) che indica una codifica errata
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();
}