2016-07-06 9 views
0

MyClass Objekt einen Arbeiter hat QObject, dass in einem anderen Thread arbeiten:Qt Exit-Ereignisses in einem anderen Thread für Arbeiter Objekt der Warteschlange

class MyClass { 
.... 
private: 
    QThread thread; 
    Worker worker; // inherits QObject 
}; 

... 

worker.moveToThread(&thread); 

Nun, wenn ich meinen thread.exit() Worker-Thread nennen stoppt sofort. Ich würde es vorziehen, alle ausstehenden Ereignisse zu beenden und dann zu beenden.

Ich habe so etwas wie "Warteschlange Ausgang" versucht:

connect(this, SIGNAL(signalFinish()), 
     &thread, SLOT(quit()),Qt::QueuedConnection); 

... 

void MyClass::finish() 
{ 
    emit signalFinish(); 
    worker.disconnect(); // do not queue any more events 
    thread.wait(); 
} 

aber es funktioniert nicht. Es wird ewig warten ...

Wie stoppe ich QThread nachdem es Event-Loop alle ausstehenden Ereignisse verarbeitet?

+0

haben Sie vielleicht einen 'QuitThread'-Slot in Ihrem Worker (der den aktuellen Thread' QThread :: currentThread() -> quit(); ') beendet und stattdessen eine Verbindung zum' thread's 'quit herstellt 'Schlitz. Auf diese Weise wird der 'QuitThread'-Slot ausgeführt, nachdem alle zuvor in der Warteschlange befindlichen Slots ausgeführt wurden. . . – Mike

Antwort

1

Der Faden und MyClass Instanzen sowohl live als im selben Thread - wahrscheinlich der Haupt-Thread:

MyClass::MyClass() { 
    ... 
    Q_ASSERT(this->thread() == thread.thread()); 

Doch die Ereignisse, die Sie dem Arbeiter Objekt an den Worker-Thread gehen sind Warteschlangen:

Die Verbindung in der Warteschlange ist genau das Falsche, denn sobald Sie auf den Arbeitsthread warten, wird die Ereignisschleife des Hauptthreads nicht ausgeführt und keine weiteren Ereignisse an den Thread ausgegeben. Der Aufruf quit wird niemals zugestellt, da er im Hauptthread geliefert wird, der Hauptthread jedoch blockiert ist.

Nutzen Sie stattdessen den Vorteil quit als threadsichere Methode. Nennen Sie es von der Arbeiter-Thread selbst:

//         vvvvvvv thread context object for the call 
connect(this, &MyClass::signalFinish, &worker, [this]{ thread.quit(); }); 
// the `quit()` will execute in `worker.thread()` 

Beachten Sie, dass der Thread-Kontext-Objekt ist ein Objekt, dessen thread() wird der Anruf in ausgeführt werden Es sollte nicht sein ein QThread Beispiel in den meisten Fällen.!

Wenn die signalFinish ausgegeben wird, wird ein QMetaCallEvent, der den Funktor oben trägt, in die Warteschlange des Arbeitsthreads eingereiht und wird ausgeführt, nachdem alle bestehenden Anruf- (und andere) Ereignisse zuerst verarbeitet wurden.

Da Sie im Hauptthread finish aufrufen, möchten Sie wahrscheinlich nicht auf den Thread warten, da dies die GUI blockiert und Ihre Anwendung nicht mehr reagiert.

Da es so aussieht, als würden Sie einem Worker-Thread Job-Artikel senden, könnten Sie besser von QtConcurrent::run bedient werden, die Job-Artikel an einen Thread-Pool übergibt und alle Threads für Sie übernimmt. Ein vollständiges Beispiel finden Sie unter this answer. Siehe this answer und that answer für einige verwandte Leckerbissen.

+0

danke! Der Aufruf von QThread :: currentThread() -> quit() vom Worker löste das Problem! – user2449761

0

Siehe this relevant StackOverflow answer.

Sie QThread::exec() Anrufs nutzen können Thread in der Ereignisschleife laufen. Der Thread wird es so lange ausführen, bis Sie dem Thread sagen, dass er beendet werden soll, indem Sie QThread::exit() aufrufen. So einiger Beispiel-Code kann wie folgt aussehen:

void DownloadWorker::run() 
{ 
    DownloadManager* pDownloadManager = new DownloadManager(this); 
    connect(pDownloadManager, SIGNAL(finished()), SLOT(exit())); 
    connect(pDownloadManager, SIGNAL(error()), SLOT(exit())); 
    pDownloadManager->download(); 
    exec(); 
} 

Dass Sie garantieren würde, dass der Thread wird nicht beendet, bis das „fertig()“ Signal Ihres Download ausgegeben wird.

Hinweis: Hier ein Beispiel, wie Sie Ihr Problem lösen können, aber ich kenne Ihren ganzen App-Code nicht. Das bedeutet, dass es keine Garantie dafür gibt, dass dieser Code sicher und konsistent ist. Sie müssen sich selbst um die Mutexe und die korrekte Synchronisation kümmern. Sei sehr vorsichtig ! Die Arbeit mit einer solchen "Low Level" -Thread-API erfordert ein gutes Verständnis von Multithreading.

+0

Ich verstehe nicht ganz, welches Problem Sie versuchen zu lösen ... –

Verwandte Themen