2016-05-28 5 views
2

ich die folgende Einstellung haben:QThread interthread Kommunikation: seltsames Verhalten Anschluss an & QThread :: beenden zu einem Lambda-vs Anschluss [& thread] {Gewinde-> quit();}

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

    // Create the DBManager that will live for the entire 
    // duration of the application 
    auto dbManagerThread = std::make_unique<QThread>(); 
    auto dbManager = std::make_unique<DBManager>(); 
    dbManager->moveToThread(dbManagerThread.get()); 
    dbManagerThread->start(); 


    // for the initialization of the application, create the 
    // InitHelper object that will utilize the DBManager 
    auto initHelper = new InitHelper(); 
    auto initHelperThread = new QThread(); 
    initHelper -> moveToThread(initHelperThread); 
    // wire InitHelper and its thread 
    QObject::connect(initHelperThread, &QThread::started, initHelper, &InitHelper::run); 
    QObject::connect(initHelper, &InitHelper::finished, [&initHelperThread] { initHelperThread->quit();}); 
    QObject::connect(initHelper, &InitHelper::finished, initHelper, &InitHelper::deleteLater); 
    QObject::connect(initHelperThread, &QThread::finished, initHelperThread, &QThread::deleteLater); 

    // wire InitHelper and DBManager 
    QObject::connect(initHelper, &InitHelper::queryDB, dbManager.get(), &DBManager::processQuery); 
    QObject::connect(dbManager.get(), &DBManager::queryResult, initHelper, &InitHelper::processQueryResult); 


    // block until all information is gathered 
    initHelperThread->start(); 
    initHelperThread->wait(); 
    std::cout << "Initialization completed." << std::endl; 

    // cleanup 
    dbManagerThread->quit(); 
    QObject::connect(dbManagerThread.get(), &QThread::finished, &a, &QCoreApplication::quit); 
    return a.exec(); 
} 

Die Idee ist, dass ich Haben Sie den DBManager, der asynchrone Datenbankzugriffe durchführt und somit in der gesamten Anwendung verwendet wird. Während der Initialisierung der Anwendung muss ich einige Informationen aus der Datenbank abrufen und dafür den bereits vorhandenen DBManager verwenden.

Da ich jedoch die Informationen aus der Datenbank benötige, um alle anderen Objekte zu erstellen, möchte ich die weitere Ausführung des Hauptthreads blockieren, bis mein InitHelper alle erforderlichen Informationen aus dem DBManager abgerufen hat.

Da der obige Code genau das tut, was er soll, glaube ich nicht, wie genau InitHelper und DBManager implementiert sind und ich habe sie hier weggelassen.

Was ich verwirrend finde, ist die Tatsache, dass ich das Lambda in der zweiten Zeile im 'wire InitHelper und sein Thread' Teil verwenden muss. Wenn ich ersetzen

QObject :: connect (initHelper, & InitHelper :: fertig, [& initHelperThread] {initHelperThread-> quit();});

von

QObject :: connect (initHelper, & InitHelper :: fertig, initHelperThread, & QThread :: beenden);

anscheinend der Thread nie heruntergefahren und so "Initialisierung abgeschlossen" wird nie auf stdout gedruckt werden.

Dies ist der Ausgang, wenn die Verbindung mit dem Lambda mit:

InitHelper: Initialization started... 
DBManager: processing query... 
InitHelper: processing query result 
Initialization completed. 

während, wenn sie direkt an den Schlitz verbindet, erhalte ich diese Ausgabe:

InitHelper: Initialization started... 
DBManager: processing query... 
InitHelper: processing query result 

Kennt jemand warum es liegt Unterschied beim Anschluss an das Lambda, anstatt direkt mit dem Steckplatz zu verbinden? Und wie kann ich die Verbindung ohne ein Lambda schreiben?

Antwort

1

In Ihrem Code:

QObject::connect(initHelper, &InitHelper::finished, [&initHelperThread] { initHelperThread->quit();}); 

ist ähnlich zu:

QObject::connect(initHelper, &InitHelper::finished, initHelperThread, &QThread::quit, Qt::DirectConnection); 

Im Grunde bedeutet es, dass Sie direkt die Funktion anstelle der Verwendung der Ereignisschleife anrufen.

Der Grund, glaube ich, dass Ihre „richtigen“ Code nicht (dh, wenn Sie die Qt :: QueuedConnection - die Standardeinstellung ist) funktioniert, weil Sie nicht die Qt-Ereignisschleife laufen begonnen haben, von a.exec();

Aufruf

Um dies zu lösen, würde ich Ihre Wait() -Funktion entfernen und Ihren "Start" -Code in eine Startup-Klasse (ein bisschen wie Ihre initHelper) verschieben. Verbinde ein Signal von dem fertiggestellten initHelper mit der start() - Funktion (oder wie immer du es nennen willst) deiner Startup-Klasse.

bearbeiten

Sie könnten in der Lage sein, dies zu tun (lesen Sie nur so ähnlich):

int ret = a.exec(); 
initHelperThread->wait(); 
std::cout << "Initialization completed." << std::endl; 
    : 
    do other stuff 
    : 
return ret; 
+0

Sie haben Recht, das Hinzufügen Qt :: Direct zum connect Anruf geschlitzten nur funktioniert gut. – Corristo

+0

Ich habe eine Bearbeitung hinzugefügt, ich habe etwas ähnliches gesehen, es könnte schneller für Sie sein:) –

+0

Ich denke, nur das Hinzufügen von Qt :: DirectConnect ist der einfachste Weg. Das Ausführen von a.exec() vor dem wait() funktioniert nicht. – Corristo