Zitat von
BAMatze:
Also eigentlich greifen sie nur auf unterschiedlich Daten zu. Einmal gibt es einen Type-Strukt für die einzelnen Punkte auf der "Welt" dieser wird im 1. Thread geändert. Der 2.Type-Strukt enthält die Daten für die erste Lebensform dieser werden im 2. Thread geändert. Und für den 3. Type-Strukt und dem 3. Thread gilt das gleiche, wie bei den ersten beiden.
Soweit ich mich erinnere, verwendet die 1. Lebensform die Welt, um sich zu ernähren - damit hast du schon mal Zugriffe aus zwei Threads auf die Welt. Wenn sich die 2. Lebensform von der ersten ernährt, hast du selbiges. Ergo: die Zugriffe auf Welt und 1. Lebensform müssen gegenseitig synchronisiert werden.
Beispiel:
Welt_aendern erhöht die Nahrung an einem Ort. Währenddessen nimmt Lebensform 1 Nahrung von diesem Ort auf. Bei zwei Threads kann dir folgendes passieren:
a)
Thread1: Welt[i,j].iNahrung := Welt[i,j].iNahrung + random(3);
Thread2: Objekt.iNahrung := Objekt.iNahrung + Welt[Objekt.ix-1,Objekt.iy-1].iNahrung;
Thread2: Welt[Objekt.ix-1,Objekt.iy-1].iNahrung := 0;
b)
Thread2: Objekt.iNahrung := Objekt.iNahrung + Welt[Objekt.ix-1,Objekt.iy-1].iNahrung;
Thread1: Welt[i,j].iNahrung := Welt[i,j].iNahrung + random(3);
Thread2: Welt[Objekt.ix-1,Objekt.iy-1].iNahrung := 0;
c)
Thread2: Objekt.iNahrung := Objekt.iNahrung + Welt[Objekt.ix-1,Objekt.iy-1].iNahrung;
Thread2: Welt[Objekt.ix-1,Objekt.iy-1].iNahrung := 0;
Thread1: Welt[i,j].iNahrung := Welt[i,j].iNahrung + random(3);
Je nach Thread-Umschaltung bekommst du ein anderes Ergebnis. Im Fall b) verschwindet sogar Nahrung. Dieses Beispiel mag vielleicht nicht so schwere Folgen haben, aber es zeigt doch die Problematik auf.
Zitat von
BAMatze:
Am Ende werden dann alle Daten zusammen gefügt. Und im letzten Schritt wird das alles komplett (Hauptthread) darzustellen.
Der Hauptthread kann erst mit der Darstellung beginnen, wenn alle anderen Threads mit ihren Berechnungen fertig sind. Zwischenzeitlich tut er so gut wie nichts. Während der Darstellung dürfen die anderen Threads aber nichts mehr an den Daten ändern. Du must den Zugriff also auch hier synchronisieren.
Zitat von
BAMatze:
und bisher wird alles hintereinander berechnet.
Auf einem 1-Prozessorsystem wird auch alles hintereinander berechnet, nur nicht in der gleichen Reihenfolge. Der Overhead für die Thread-Umschaltung erhöht die gesamte Laufzeit allerdings. Du kannst also theoretisch nur dann an Laufzeit gewinnen, wenn mindestenes zwei Prozessoren gleichzeitig an deiner Simulation werkeln und der Overhead diesen Vorteil nicht auffrisst.
Ich bin grundsätzlich ein Freund von Threads, verwende sie aber meistens nur um die Berechnungen von der
GUI zu trennen, damit die Anwendung auch noich bedienbar bleibt. Meistens erhält man damit auch eine einfache Möglichkeit, die Berechnung vorzeitig zu beenden.
Wenn schon Threads, dann wäre mein Vorschlag: Die gesamte Simulation in der Execute-Methode eines abgeleiteten TThread-Objekts zu verfrachten, für die Ausgabe werden in besteimmten Zeitabständen Bitmaps gemalt. Der Zugriff auf die Bitmap vom Hintergrund- und Hauptthread wird über ein geeignetes Objekt synchronisiert (z.B. CriticalSection). Die Aktualisierung des Treeviews würde ich komplett rausnehmen, da diese bei entsprechend vielen Elementen gehörig in die Knie geht. Für die verwendete Art der Darstellung täte es übrigens auch ein TMemo.