Frage zu Qthread und Qmutex

Alles rund um die Programmierung mit Qt
Antworten
Rumbert
Beiträge: 48
Registriert: 25. Mai 2009 18:28
Wohnort: Witten

Frage zu Qthread und Qmutex

Beitrag von Rumbert »

Hallo NG,

ich glaube, das was ich gebaut habe ist deutlich zu umständlich und dazu noch fehlerhaft. Evtl. kann mir jemand eine elegantere Lösung zeigen.
Was ich versucht habe sieht so aus:

Code: Alles auswählen

void Processor::run()
{
	bool ever = false;
	mutex.lock();
	if (serverOn)
		ever = true;
	else if (!serverOn)
		ever = false;
	mutex.unlock();

	while (ever)
	{
                ... 
		processMessageFromQueue();
		...

		msleep(2);

		mutex.lock();
		if (serverOn)
			ever = true;
		else if (!serverOn)
			ever = false;
		mutex.unlock();
	}
}

void Processor::stopTheThread()
{
	mutex.lock();
	serverOn = false;
	mutex.unlock();
        ...
}
Die while-Schleife läuft in einem Thread solange serverOn true ist. Aus dem Hauptthread will ich nun diese Variable auf False setzen damit der thread dann beendet wird. Das Problem liegt nun schon darin, dass ja auf die Variable mutex von zwei verschiedenen Threads aus zu gregriffen wird...

Hat jemand einen Tipp?

Grüße Rumbert
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Und wo liegt jetzt das Problem? stopTheThread() vom Hauptthread aus aufrufen sollte doch klappen - oder?
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Rumbert
Beiträge: 48
Registriert: 25. Mai 2009 18:28
Wohnort: Witten

Beitrag von Rumbert »

Ab und zu stürzt er bei mutex.lock() in der run-Methode ab. Muss ich zwei verschiedene Mutexe nehmen, einen für die run-Methode und einen für die StopTheThread-Methode?
Des Weiteren erscheint mir meine Art von Code-Gerüst etwas unbeholfen und zu sehr "gefrickelt", so als wenn ich die elegante Lösung übersehe...

Grüße Rumbert
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Das Codegerüst ist ok - außer dass man ggf. ever und serverOn zusammenfassen könnte.
Zwei verschiedene Mutex würde das ganze ja ad asurdum führen. Ein Crash kann eigentlich nicht sein - zumindest nicht aufgrund des Mutex. Da muss was anderes faul sein.
Zur Übersichtlichkeit würde ich es so schreiben

Code: Alles auswählen

bool shouldProcessMessages()
{
  QMutexLocker l(&mutex);
  return !serverOn;
}
void Processor::run()
{
   while (shouldProcessMessages())
   {
      ...
      processMessageFromQueue();
      ...

      msleep(2);
   }
}

void Processor::stopTheThread()
{
   QMutexLocker l(&mutex);
   serverOn = false;
}
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Rumbert
Beiträge: 48
Registriert: 25. Mai 2009 18:28
Wohnort: Witten

Beitrag von Rumbert »

Vielen Dank für Dein Code-Beispiel!

Grüße Rumbert
Rumbert
Beiträge: 48
Registriert: 25. Mai 2009 18:28
Wohnort: Witten

Beitrag von Rumbert »

hmm.. ein Problem habe ich dennoch mit der Lösung, und zwar manchmal stürzt das Programm beim beenden des Threads ab:

Code: Alles auswählen

void Processor::stopTheThread()
{
   QMutexLocker l(&mutex);  //  <--- Absturz
   serverOn = false;
} 
mutex existiert nicht mehr richtig und verweist in die Pampa.
Zuvor bekomme ich als Output die Meldung:
"QThread: Destroyed while thread is still running"
hmm nur warum...

und wenn ich ein msleep(10) noch ans Ende der Methode packe, scheint es zu gehen (soll heißen, ich habe noch keinen Absturz damit provozieren können).

Mir ist das nicht geheuer mal irgendwo ein msleep zu schreiben, weil er sonst ab und zu abstürzt...
Gibts da ne logische Erklärung für oder nen korrekten weg das Problem zu umgehen?

Grüße Rumbert
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Wie beendest Du den Thread denn? Mit QThread::terminate() oder so?
Warning: This function is dangerous and its use is discouraged. The thread can be terminate at any point in its code path. Threads can be terminated while modifying data. There is no chance for the thread to cleanup after itself, unlock any held mutexes, etc. In short, use this function only if absolutely necessary.
Wenn es nur per stopTheThread() gestoppt wird dann kommt die Warnung von Qt nicht. Also mehr Code würde ich sagen.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

wenn du den thread mit StopThread stoppst, weisst du den thread ja nur an, such selbst zu beenden.
Wenn du sichergehen willst, das der thread auch ausgelaufen ist ... musst du mit nem wait hinterher auf das beenden des threads warten ....

Das sympthom was du beschreibst passierst meisst, wenn der eine thread den anderen beendet, nicht richtig wartet bis er ausgelaufen ist, und dann trotzdem irgendwie ins aufrauemen laueft, wo der QThread und vor allem der Mutex geloescht wird. Dann kommt der eigentlich beendete thread noch mal zum zug und der "haengt noch" im Mutex ... der ja eigentlich gar nimemr existiert.


Code: Alles auswählen

void Processor::stopTheThread()
{
   {
        QMutexLocker l(&mutex);  //  <--- Absturz
        serverOn = false;
    }
    /// warten bis der thread wiurklich zu ende ist ... 
    /// mit timeout der gross genug ist 
    if(wait(10000))
    {
          /// thread hat sich wieder erwarten doch ned selbst beendet
          /// also die grobe Kelle auspacken 
          terminate();
          /// und noch kurz was warten 
          msleep(100)
    }
} 
WIe gesagt, mach ned viel mit der QT bei Threads, aber so aehnlich sehen meine stopproceduren auch aus, abgesehen von serveron, das wird bei mir was anderes sein, meistens ne "Eventvariable".

der bool serveron mit nem mutex schuetzen iss fast overkill.
Ja er muss geschuetzt werden, oder man verwendet gleich atomics ...
die sind schneller und der mutex entfaellt, man laeuft ned aufn spinlock.
Nen mutex zu blocken und wieder freizugeben wird sicher viel mehr zeit beanspruchen als die variable zu schreiben ^^

Schau dir mal QAtomicInt an ....

Weiterhin:
while (ever)
{
...
processMessageFromQueue();
...

msleep(2);
Du pollst: Das ist meist die Mutter aller Probleme beim multithreading. (manchmal muss man es, aber man sollt es vermeiden wo es geht!)
processMessageFromQueue wer beschreibt die , bzw wer liefert die nachrichten da ein?
Kann der nich nen event setzen, wenn er nachrichten da reingepumpt hat ? Dann kommst vom pollen weg, und dein Programm wird ne menge performanter ....

Ciao ....
Rumbert
Beiträge: 48
Registriert: 25. Mai 2009 18:28
Wohnort: Witten

Beitrag von Rumbert »

Code: Alles auswählen

void CommunicatorWindow::slotStopDeleteProcessor()
{
	if (NULL != pProcessor)
	{
		pProcessor>stopTheThread();
		delete(pProcessor);
		pProcessor= NULL;
	}
        ...
}


void Processor::stopTheThread()
{
   QMutexLocker l(&mutex);  //  <--- Absturz
   serverOn = false;
} 

ich clicke in der GUI auf einen Button der mit "slotStopDeleteProcessor" connected ist und damit wird dann der Thread beendet. Ich weiß nicht ob der Code Ausschnitt jetzt etwas mehr hilft?

Grüße Rumbert
[/code]
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Denk ist genau dein problem:

- pProcessor>stopTheThread(); // du weisst den thread an sich zu beenden, wartest aber ned drauf
- delete(pProcessor); // du loeschst alle variablen die mit dem thread zu tun haben

wenn du halt pech hasst, lauft das stop und das delete des einen threads in einem stueck durch ... dein zu beendender thread wacht danach auf .. und du hasst ihm scho alles unterm hintern weggezogen :-)

Ciao ...
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Wenn er das Signal "finished()" mit dem Slot "deleteLater()" verbindet, braucht er nicht mal darauf zu warten...
Antworten