Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Do Jul 03, 2025 13:52

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Threads synchronisieren
BeitragVerfasst: So Jun 20, 2010 13:11 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
Hallo,

In meinem aktuellen Projekt nutze ich Java in Verbindung mit OpenGL (JOGL).
Dort gibt es eine Klasse namens Animator, die einen Thread bereitstellt, der sich um das Updaten von OpenGL kümmert. In diesem Thread werde ich also sämtliche Darstellungen vornehmen.
Die Programmlogik hingegen, möchte ich in eine andere Klasse, bzw. am besten sogar in einen anderen Thread auslagern. Jetzt frage ich mich, wie ich diese beiden Threads am besten synchronisieren kann.
Die Idee war es, dem Render Thread eine Liste von Objekten zu geben, die dieser dann zeichnen soll.

Ich könnte nun zu jedem Objekt eine weitere Klasse hinzufügen, in der die Informationen für die Darstellung gespeichert sind. In einem Observer-Modell könnte nun die Logik-Klasse der Darstellungs-Klasse die Änderungen mitteilen. Die Methoden der Darstellungs-Klasse würden dann alle synchronized gemacht werden und der Renderer könnte problemlos auf diese zugreifen.
Da die Logik aber primär Auswirkungen auf die Darstellung hat, kann ichs auch in eine Klasse packen.

Ist das sinnvoll, oder gibt es eine bessere Methode?

Gruß,
Seth


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Threads synchronisieren
BeitragVerfasst: So Jun 20, 2010 15:23 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
Ahoi,

1. wisse, dass JOGL langsam ist. Ich würde eher lwjgl nehmen. Das ist performanter.

2. Im Wesentlichen musst du doch nur im Renderthread eine Queue von Runnables haben, in die du aus den anderen Threads was reinstopfst. Guck dich da mal im java.util.concurrent package um, das hat da sehr gute BoundedQueues und Executoren für Threads, womit das ziemlich einfach ist. Im Renderthread gehst du dann einfach Runnable für Runnable deine Queue durch und führst es aus. In den Runnables sind dann die Aufrufe an lwjgl drin (= aka: Dein Rendercode).

3. Sehr zu empfehlen ist das Buch "Concurrency in practice", wenn du was mit Concurrency in Java machen möchtest

4. Ich würde mich gar nicht so sehr darauf festlegen, dass das Datenmodell und die Darstellung so eng aneinander gekoppelt sind und dauernd über Observer voneinander erfahren. Das Observer-Pattern ist schon länger veraltet (aus gutem Grund) und wenn du exzessiv synchronisieren musst, geht die Performance auch eher Richtung Keller ;)

5. Vergiss nicht: Multi-Threaded ist wesentlich schwerer als Single-Threaded. Ich würde da sehr genau abwägen, ob sich das lohnt.

Hope this helps
~ Frase

_________________
"Für kein Tier wird so viel gearbeitet wie für die Katz'."


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Threads synchronisieren
BeitragVerfasst: So Jun 20, 2010 15:40 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
1. JOGL benutze ich primär, weil ich diverse Probleme mit der lwjgl hatte. Performance spielt keine Rolle, da es sich nur um eine 2D Anwendung mit geschätzten 30-40 Polygonen handelt. Nichts Großes ;)

2. Klingt sehr interessant. Implementieren dann praktisch die Objekte, die ich zeichnen möchte das Interface Runnable, oder wie darf ich mir das vorstellen?

3. Schau ich mir mal an, danke

4. Ja das hab ich mir inzwischen auch gedacht und die Idee mit den Observern verworfen.

5. Nein lohnt sich nicht ;) Momentan ist es halt wie folgt:

main Methode erzeugt Animator Objekt (da kommt Thread #1 her) und eine Game Klasse, die hat eine Endlos-Update Schleife in Thread #2und eine draw() Methode. Beide sind synchronized.
Um das ganze nun Single-Threaded zu machen, müsste ich ich auf das Animator Objekt verzichten oder davon erben. Ist das sinnvoll? Ich würde dann den klassischen Ansatz wählen:
Code:
main() {
  dt = timer.update();
  game.update(dt);
  renderer.render();
}

Momentan laufen die halt parallel.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Threads synchronisieren
BeitragVerfasst: So Jun 20, 2010 16:08 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
Wegen dem Runnable: Genau so macht es übrigens der EventDispatchThread von Swing. Man macht ja alle GUI-Operationen (in Swing) im EDT und dafür gibt's entsprechende Hilfsmethoden (wie z.B. invokeLater):
Code:
SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        button.setText("Yay!");
    }
}


Und analog dazu könntest du dir halt ein RenderThread.invokeLater(...) machen. Das muss auch nicht zwingend Runnables nehmen, aber die bieten sich halt an :)

Könnte also so aussehen:
Code:
RenderThread.invokeLater(new Runnable() {
    @Override
    public void run() {
        gl.begin();
        gl.vertex3f(...); // Blabla
        gl.end();
    }
}


Alle Klarheiten beseitigt? ;)
~ Frase

_________________
"Für kein Tier wird so viel gearbeitet wie für die Katz'."


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Threads synchronisieren
BeitragVerfasst: So Jun 20, 2010 17:08 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
Fast alle Klarheiten ;)

Das ist jetzt schon fast Off Topic. Aber wie läuft das, wenn ich es in einem einzigen Thread machen will?

So siehts momentan aus:
Code:
Frame frame = new Frame();
GLCanvas canvas = new GLCanvas(caps);
canvas.addGLEventListener(new Renderer());
frame.add(canvas);
final Animator animator = new Animator(canvas);
animator.start();

In der Renderer Klasse (die GLEventListener implementiert) gibt es dann diese Methode:
Code:
public void display(GLAutoDrawable drawable) {
}
die afaik in dem Animator Thread läuft. In dieser Methode möchte ich aber keine Logik-Berechnungen machen.
Ich könnte alternativ den Animator weglassen und display() selbst manuell aufrufen, aber das ist glaube ich nicht Sinn der Sache.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Threads synchronisieren
BeitragVerfasst: So Jun 20, 2010 17:41 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
Öh... ich bin mir nicht ganz sicher, deine Frage zu 100% geschnallt zu haben,

aber angenommen, du willst das alles in einem Thread machen (z.B. alles im RenderThread) und du nutzt den Code von oben, dann klappt das natürlich nicht: Denn du schreibst damit etwas auf die "ToDo-Liste" des Threads, der diese Liste auch wieder abarbeiten muss. Und entweder macht der Thread die Abarbeitung von dem Zeug _oder_ das Hinzufügen von ToDo-Einträgen ;) Wenn er abwechselnd was hinzufügt und dann direkt danach wieder abarbeitet, ist das ganze etwas witzlos.

Da du (z.B. beim EDT von Swing) auch auf die Abarbeitung eines solchen Runnables warten kannst (mit invokeAndWait statt invokeLater), ist es sogar wichtig, dass es zwei verschiedene Threads sind: Würdest du nämlich mit invokeAndWait auf die Abarbeitung im selben Thread warten, würdest du ewig warten (Das oft zitierte Deadlock): Du würdest nämlich auf dich selbst warten.

Deswegen prüft der EDT von Swing das beispielsweise und wirft eine IllegalStateException iirc. Und dafür gibt's beim EDT auch diese tolle Methode SwingUtilities.isEventDispatchThread() (oder so ähnlich).

~Frase

_________________
"Für kein Tier wird so viel gearbeitet wie für die Katz'."


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Threads synchronisieren
BeitragVerfasst: So Jun 20, 2010 17:48 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
Ja das war was ich meinte. Die eigentlich Frage war: Wie stelle ich am besten an, dass ich Logik und Rendering nun in einen Thread packen kann?

Zu Animator steht in der Doc folgendes:
Zitat:
The Animator class creates a background thread in which the calls to display() are performed. After each drawable has been redrawn, a brief pause is performed to avoid swamping the CPU, unless setRunAsFastAsPossible(boolean) has been called.

D.h. ich könnte folgendes probieren:
Code:
while (true) {
  dt = timer.update();
  game.update(dt);
  renderer.display();
  Thread.sleep(10);
}

Oder? Dann hatte die Gui zwar immer noch ihren eigenen Thread, aber das sollte ja nicht weiter schlimm sein.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Threads synchronisieren
BeitragVerfasst: Mi Jul 07, 2010 16:23 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
Ich verwende jetzt ausschließlich einen Thread (bin inzwischen sogar wieder auf den Animator umgestiegen) und rufe meine update() sowie meine render() Methode beide in
Code:
public void display(GLAutoDrawable drawable) {
  game.updateGame();
// ... hier steht noch mehr
  game.render(this, gl, width, height);
}


auf. In meiner update() und render() Methode iteriere ich jeweils über eine Liste (die selbe) und bekomme wenn ich Listenelemente löschen möchte (meistens) eine ConcurrentModificationException.
Aber müssten die nicht, dadurch dass beide von display() aufgerufen werden, im selben Thread laufen? Wie kann es da zu so einer Exception kommen?

In update() passiert etwa so etwas:

Code:
for (Entity e : entities) {
  if (player.collidesWith((ICollidable)e)) {
    entities.remove(e);
  }
}

Das Problem tritt sogar dann noch auf, wenn ich um den gesamten Block ein synchronized mache.

Wenn ichs so mache, scheint überhaupt nichts mehr zu passieren (weißes Bild):

Code:
  for (Iterator<Entity> it = entities.iterator(); it.hasNext();) {
    if (player.collidesWith((ICollidable)it)) {
      entities.remove(it);
    }
  }

hm ich lese grad, dass es normal ist, dass der fehler auftaucht, wenn man während des iterierens löschen, will aber mit nem iterator solls angeblich gehen ...

so gibts wieder die exception:
Code:
Iterator<Entity> it = entities.iterator();
while (it.hasNext()) {
  Entity e = it.next();
  if (player.collidesWith((ICollidable)e)) {
    entities.remove(e);
  }
}


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Threads synchronisieren
BeitragVerfasst: Mi Jul 07, 2010 16:59 
Offline
DGL Member

Registriert: Di Mai 24, 2005 16:43
Beiträge: 710
ok wenn man it.remove() nimmt, scheint es zu gehen ;)


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Threads synchronisieren
BeitragVerfasst: Do Jul 08, 2010 22:25 
Offline
Forenkatze
Benutzeravatar

Registriert: Mi Okt 22, 2003 18:30
Beiträge: 1945
Wohnort: Närnberch
Programmiersprache: Scala, Java, C*
Jupp ;) Die Iteratoren in Java sind zum Großteil fail-fast. Das ist exzessiv in der Javadoc dokumentiert. Besser kann ich's eigentlich auch nicht ausdrücken.

Das Verhalten hängt von der unterliegenden Implementierung ab. Die ArrayList z.B. ist nicht thread-safe (Dafür gibt's Vektor). Genaueres steht da in der Javadoc dazu. Ab dem fett markierten "not threadsafe" ;)

Speziell das hier ist interessant für dich (und hat mit Threads übrigens absolut gar nichts zu tun):
Javadoc hat geschrieben:
The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.

_________________
"Für kein Tier wird so viel gearbeitet wie für die Katz'."


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.018s | 17 Queries | GZIP : On ]