Anzeige:
Ergebnis 1 bis 12 von 12

Thema: SWT Widget in Thread updaten: Das ganze Programm hägt

  1. #1
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Ort
    Nettetal
    Beiträge
    72

    SWT Widget in Thread updaten: Das ganze Programm hägt

    Hi,
    Ich bastel mir grad nen kleinen Daemon, der den Netzwerktraffic unter Linux loggt und auch aktuelle Transferraten übers Netzwerk bereitstellt.

    Ich bin grade dabei einfach mal ein universalprogramm zu schreiben, wo ich mit mit einem Server verbinden kann und einfach nur Strings senden und empfangen kann.

    Allerdings gibts da ein Problem:
    Ich führe die Methode readLine() des BufferedReaders vom Socket in einem Thread aus. Diese Methode wartet so lange, bis irgendwas ankommt. Das Programm würde ohne Thread einfach stehen bleiben, bis was ankommt. Deswegen der Thread.
    Zuerst hab ich immer SWTExceptions bekommen, da SWT den Zugriff auf Widgets ausserhalb des GUI Threads nicht erlaubt. Das hab ich mitlerweile mit der asyncExec(Runnable) Methode erledigt.
    Allerdings wird der Thread gestartet und das Prog hängt dann. Es bleibt genau beim readLine() hängen. Wobei die GUI aber im anderen Thread weiterlaufen sollte. Also hab ich jetzt dasselbe, was ich auch ohne Threads hätte
    Sieht so aus, als ob SWT immer auf das Ende des Threads wartet, bevor andere Operationen ausgeführt werden.

    Gibt es da eine Lösung?
    In AWT/Swing hab ich das ganze auch schonmal so gelöst. Nur SWT ist anscheinend ein wenig genauer und extravaganter

    Code:
    display.asyncExec(new Runnable()
    		{
    			public void run()
    			{
    				try
    				{
    					while(true)
    					{
    						String s = reader.readLine();
    						System.out.println("receiving: " + s);
    						txt_receive.append(s + System.getProperty("line.separator"));
    					}
    				}
    				catch(Exception e)
    				{
    					outputException(e);
    				}
    			}
    		});

  2. #2
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Ich denke du hast das Konzept von SWT/asyncExec/syncExec noch nicht ganz verstanden.

    Der Aufbau ist folgender:
    - Du hast einen GUI-Thread der die Nachrichtenverarbeitungsschleife ausführt (irgendwas.readAndDispatch() oder so war das).
    - Du hast eine beliebige Zahl nicht-GUI Threads die einfach so fröhlich vor sich hin laufen.

    Bis hier hin kommt das syncExec/asyncExec-Zeugs nicht ins Spiel. Die nicht-Gui-Threads sind ganz normale Threads.

    Nun hast du folgendes Problem: von den nicht-GUI Threads kannst du nicht auf die GUI zugreifen. Das geht ausschliesslich vom GUI-Thread aus.
    Die Lösung - und hier kommt syncExec/asyncExec ins Spiel - besteht darin dass dein nicht-GUI-Thread dem Gui-Thread sagt was der machen soll, indem er asyncExec() aufruft und ein entsprechendes Runnable übergibt.
    Dieses Runnable-Objekt wird nicht als eigener Thread ausgeführt, sondern viel mehr im GUI-Thread wie eine normale Methode ausgeführt.

    Dies erklärt auch dein Problem: Der GUI-Thread guckt in seine Nachrichtenverarbeitungsschleife und findet dort ein asyncExec() was er ausführen soll. Also macht er das - nur bleibt er dort drin hängen und hängen und hängen.

    Die Lösung: Du machst ein asyncExec() das ausschliesslich den Methodenaufruf zum updaten der GUI beinhaltet und auf keinen Fall mehr Code (und schon gar nicht Code der blockiert wie obiges lesen).

    Der Unterschied zwischen syncExec() und asyncExec() besteht darin dass ersteres für den nicht-GUI Thread synchron, zweiteres für ihn asynchron ausgeführt wird. Das heisst bei syncExec() fährt der nicht-GUI Thread erst dann weiter wenn der GUI-Thread das Runnable fertig ausgeführt hat.

    MfG Peschmä
    Geändert von peschmae (14-04-2006 um 09:34 Uhr)
    The greatest trick the Devil ever pulled was convincing the world he didn't exist. -- The Usual Suspects (1995)
    Hey, I feel their pain. It's irritating as hell when people act like they have rights. The great old one (2006)

  3. #3
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Ort
    Nettetal
    Beiträge
    72
    Ah OK, dann mach ich nen synchronisierten Thread, der den empfangenen Text immer an eine Variable anhängt uns die asyncExec Methode lass ich einfach, wenn sich die Variable geändert hat die GUI updaten.
    So sollte es gehen.

  4. #4
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Ort
    Nettetal
    Beiträge
    72
    Hmm ich bekomms nicht hin.
    Wie mach ich das denn jetzt am besten?
    Ich find massig Beispiele zu AWT/Swing mit Google, aber nichts zu SWT...

    edit:
    Ich habs so weit hinbekommen, dass ich senden kann. Der Server antwortet dann mit dem selben String (bis jetzt... nur zum testen) und dieser wird über einen Thread in ne Variable gesteckt.
    Jetzt muss dieser String nur noch an den Text im TextBox Widget angehangen werden. Und ich hab keine Ahnung, wie ich das machen kann, ohne das das Programm sich irgendwo in ner Endlosschleife verrennt oder endlos wartet und nicht mehr reagiert.
    Geändert von Andy1988 (14-04-2006 um 14:04 Uhr)

  5. #5
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Der Worker Thread gibt alles was er bekommt in einen synchronisierten Puffer, zB eine ArrayList

    Der GUI Thread sieht dort immer nach ob was da ist und wenn ja, nimmt er es raus und updated die GUI

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  6. #6
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Ort
    Nettetal
    Beiträge
    72
    Code:
    private void updateGui()
    	{
    		try
    		{
    			while(true)
    			{
    				if(lastReceived != null)
    				{
    					System.out.println("adding to control: " + lastReceived);
    					txt_receive.append(lastReceived + System.getProperty("line.separator"));
    					lastReceived = null;
    				}
    			}
    		}
    		catch(Exception e)
    		{
    			outputException(e);
    		}
    	}
    Hmm... Wenn ich das so mache dann hängt wieder alles, weil er immer in der Schleife bleibt!

  7. #7
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Der Arbeitsthread darf ansich eh in der Schleifen "hängen", er wartet dort ja auf Input vom Stream (der im letzten Codeschnipsel vermutlich der Einfachheit halber weggelassen wurde)

    Der GUI Thread muß entweder benachrichtig werden, oder erstmal einfacher, den sychronized Container pollen.
    Sollte dabei nicht hängen.

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  8. #8
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Ort
    Nettetal
    Beiträge
    72
    Habt ihr vielleicht mal nen Codeschnipsel oder so?
    Das ist das erste richtige SWT Programm, was ich schreibe.

    Und nö, die Methode ist eigentlich komplett. Das lesen vom Stream wird in nem anderen Thread erledigt. der setzt nur die Variable.

  9. #9
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Ort
    Nettetal
    Beiträge
    72
    So...
    ich hab jetzt einfach nen timer erstellt, der jede ms ausgeführt wird. Das ist zwar nicht besonders sauber, aber es funktioniert erstmal.

    Kann vielleicht aber doch noch jemand einen Codeschnipsel posten? Eine bessere Lösung muss es geben.

  10. #10
    Registrierter Benutzer
    Registriert seit
    16.09.2001
    Beiträge
    1.182
    Natürlich hängt er in der Schleife, ist ja auch eine Endlos-Schleife.
    Da darfst nicht im Event-Thread eine blockierende Aktion durchführen, ausserdem ist von derartigem polling sowieso abzuraten. Java-IO ist von sich aus blockierend und NIO event-basiert, da musst du nie selbst pollen.

    1.) In eigenem Thread alle Nachrichten in irgendein Container-Object einlesen
    2.) Klase die Runnable implementiert erzeugen (kann auch inner-class sein), welcher du bei erzeugung das Container-Object enthält mitgibst.
    3.) In der run-methode dieser neuen Klasse deine SWT-Controls mit den Daten des Container-Objects (z.B. ArrayList) updaten/einfügen.
    Geändert von Lin728 (21-08-2017 um 15:01 Uhr)

  11. #11
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Ort
    Nettetal
    Beiträge
    72
    Genau so hatte ich es vor!
    Nur leider lässt mich SWT nicht auf Widgets/Controls von einem anderen Thread aus zugreifen, als von dem Thread aus, der auch dieses Control verwaltet/erzeugt hat! Wenn ich diesen Thread in die "Poll-Schleife" hänge ises vorbei -> Endlosschleife

    Genau da liegt das Problem. So, wie du es beschrieben hast geh ich mit AWT/Swing immer vor. SWT ist da leider etwas komplizierter.

    Bis jetzt hab ich die Übergangslösung mit dem Timer, aber das gefällt mir irgendwie nicht

  12. #12
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Die Lösung ist, wie ich schon oben geschrieben habe, dass du den Code zum Updaten der GUI vom Hintergrundthread her mit Hilfe eines "asyncExec" oder eines "syncExec" an den Hauptthread weitergibst. Was funktioniert daran denn nicht?

    MfG Peschmä
    The greatest trick the Devil ever pulled was convincing the world he didn't exist. -- The Usual Suspects (1995)
    Hey, I feel their pain. It's irritating as hell when people act like they have rights. The great old one (2006)

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •