# 2 Threads nacheinander. Einer terminiert, der andere nicht.



## Ralf1007 (18. Sep 2008)

Hallo.

Schaut euch bitte folgende zwei Methoden an:


```
protected void onCreate(eHomeBase newObject) {

		Display.getDefault().syncExec(new Runnable() {

			@Override
			public void run() {
				refreshChildren();
			}
			
		});
}

protected void onDelete(Object model) {

		Display.getDefault().syncExec(new Runnable() {

			@Override
			public void run() {
				refreshChildren();
			}
			
		});
	}
```

Im Programmablauf ergibt es sich, dass diese beiden Methoden nacheinander aufgerufen werden. Zuerst onCreate, weil etwas erstellt wurde, dann nach kurzer Zeit onDelete, weil ein anderer Vorgang bewirkt hat, dass etwas gelöscht wurde.
In beiden Methoden wird ein Thread geöffnet, der nach meiner Interpretation dann beendet ist, wenn refreshChildren() abgearbeitet wurde. Die Abläufe darin sind recht komplex und über mehrere Ebenen verteilt, weshalb ein posten dieser Methode keinen Sinn macht.
Ausgangssituation steht.

Nun gibt es beim Aufruf von onCreate kein Problem. Der Thread wird gestartet und ordnungsgemäß beendet. Das ist wenigstens das, was ich glaube  Beim Aufruf von onDelete wird der Thread gestartet, terminiert aber nicht, sodass das komplette Programm bis in alle Ewigkeit (also bis ich das Programm per Taskmanager oder rotem Eclipse-Knopf schliesse) hängt. Ich könnte mir das so erklären, dass refreshChildren nicht terminiert. Das ist aber ohne die Ausführung in einem eigenen Thread nicht der Fall.

Der Grund, weshalb ich diesen Weg der Ausführung wähle, ist, dass ich in bestimmten Fällen eine SWTException wegen Invalid Thread Access bekomme. Irgendwie muss ich diese in den Griff bekommen und das erscheint mir als die richtige Variante.

Hat jemand von euch eine Idee, weshalb der zweite Thread offensichtlich nicht terminiert? Muss ich vielleicht etwas mit dem Display machen, damit das so funktioniert?

Ich bedanke mich bei jedem, der sich die Mühe macht mir zu helfen.

MfG,

Ralf


----------



## Wildcard (18. Sep 2008)

Wenn du wirklich einen Thread öffnen würdest, dann würdest du eine InvalidThreadException bekommen, weil nur der SWT Thread die Widgets verändern darf (wie bei Swing auch). 
Das tust du aber nicht, weshalb man mit dem Rest deiner Aussagen nichts mehr anfangen kann.


----------



## Ralf1007 (18. Sep 2008)

Ich nutze GEF. Was GEF innen drin tut oder unterlässt, entzieht sich leider meiner Kenntnis. Offensichtlich aber wird ein neuer Thread geöffnet, der nicht der SWT UI Thread ist, denn sonst würde ich diesen Fehler nicht bekommen. Die passende Fehlermeldung ist dann eine "org.eclipse.swt.SWTException: Invalid thread access ". Dieser nicht-SWT-UI-Thread ruft dann die o.g. Methoden auf und verursacht die Exception.

Versuche ich das Problem wie oben beschrieben zu lösen, passiert das nicht mehr, dafür terminiert der zweite in onDelete geöffnete Runnable nicht.

Besser kann ich es leider nicht erklären. Wenn das nicht reicht, muss ich anders klarkommen.

Gruß,

Ralf


----------



## Wildcard (18. Sep 2008)

Nein, was du über Display#(a)syncExec startest wird in den Dispatch Thread verschoben, es wird kein neuer Thread gestartet.
Sollte tatsächlich wie du sagst das 'Runnable terminieren', dann würde das bedeuten das dein GUI Thread terminiert, denn dort wird es ausgeführt.


----------



## Wildcard (18. Sep 2008)

Ralf1007 hat gesagt.:
			
		

> Ich nutze GEF. Was GEF innen drin tut oder unterlässt, entzieht sich leider meiner Kenntnis. Offensichtlich aber wird ein neuer Thread geöffnet, der nicht der SWT UI Thread ist, denn sonst würde ich diesen Fehler nicht bekommen. Die passende Fehlermeldung ist dann eine "org.eclipse.swt.SWTException: Invalid thread access ". Dieser nicht-SWT-UI-Thread ruft dann die o.g. Methoden auf und verursacht die Exception.


Im übrigen weiß ich das eine oder andere über GEF, es wird also für uns beide leichter wenn du weniger Vermutungen anstellst und dafür mehr ins Detail gehst. (Nicht böse gemeint, ich bin da lediglich pragmatisch :wink: )


----------



## Ralf1007 (18. Sep 2008)

Okay. Das ist doch ein Ansatzpunkt.

Wenn ich im betreffenden Fall vor und hinter das Display#syncExec ein sysout mache, wird das dahinter nicht mehr ausgegeben. Das sagt mir, dass diese Codezeile nicht mehr erreicht wird. Zudem hängt das Programm.

Also bleibt er dann im GUI-Thread hängen oder wie muss ich das verstehen?

Mir fehlt, glaube ich nur dieser eine gedankliche Schritt. Den Rest kann ich mir dann selber zusammenbasteln, wie ich hoffe.

Danke für deine Hilfe.

Ralf

EDIT: Würde ich die Doku mit offenen Augen lesen, hätte ich gewusst, dass kein neuer Thread gestartet wird. Mein Fehler.


----------



## Wildcard (18. Sep 2008)

onDelete und onCreate sind vermutlich die Methoden die aufgerufen wird wenn sich am Model etwas ändert (in deinem EditPart vermutlich?)?
Sagen wir das onCreate Event wird von einem non-ui Thread getriggert (sollte eigentlich schonmal nicht, der erste Fehler ist also womöglich schon dort).
Nun willst du refreshChildren aufrufen, was natürlich im UI Thread ausgeführt werden muss. Mit syncExec blockst du den Thread bis der UI Thread zurückkehrt.
Beim refreshChildren wird nun eine Änderung festgestellt die (womöglich über 3 Ecken) onDelete triggert, diesmal jedoch aus dem UI Thread.
Wieder ein syncExec und diesmal lässt du den UI Thread auf sich selbst warten und hast somit einen Deadlock.
Das sind alles nur Vermutungen, weil ich zu wenige Details kenne, aber eine mögliche Erklärung.
Auf syncExec solltest du wo immer möglich verzichten, lieber asyncExec.
Höchstwahrscheinlich aber solltest du dir überlegen ob das event wirklich von einem non-ui Thread getriggert werden sollte, oder ob nicht dort schon das asyncExec hingehört.


----------



## Ralf1007 (18. Sep 2008)

Wow, danke. Das klingt alles sehr schlüssig und deine Vermutungen treffen zu, soweit ich das einzuschätzen vermag. Ich werde jetzt erstmal schlafen gehen, mir deinen Gedankengang morgen früh aber nochmal zu Gemüte führen. Ich denke, dass du mich damit aber auf den Lösungsweg gebracht hast. Danke dafür, ich melde mich dann nochmal.

Gute Nacht!


----------



## Ralf1007 (24. Sep 2008)

Ich habe versprochen mich nochmal zu melden 

Nach ausführlicher Lektüre des Artikels 
http://book.javanb.com/swt-the-standard-widget-toolkit/ch05lev1sec7.html
war alles klar. Oben beschriebenes Problem wird erstens dadurch behoben, dass ich asyncExec nutze. Zum Zweiten muss ich das GUI-Update vom Thread, in dem ich mich befinde, abhängig machen. Nämlich ganz normal, wenn ich mich im GUI-Thread befinde und mit asyncExec, falls das nicht der Fall ist.

Ich empfehle auf jeden Fall den Artikel zu lesen bei solchen Problemen. Der macht die Chose durchsichtig 

Danke an Wildcard für den Schubs in die richtige Richtung.

MfG,

Ralf


----------



## Wildcard (24. Sep 2008)

Ralf1007 hat gesagt.:
			
		

> Zum Zweiten muss ich das GUI-Update vom Thread, in dem ich mich befinde, abhängig machen. Nämlich ganz normal, wenn ich mich im GUI-Thread befinde und mit asyncExec, falls das nicht der Fall ist.


Hmm, jein. In den meisten Fällen ist es sinnvoller die model-änderung selbst über asyncExec durchzuführen, damit keiner der Listener jemals mit einem anderen Thread in Berührung kommt.


----------

