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

Aktuelle Zeit: Di Mai 21, 2024 17:48

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



Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: HILFE! (Multithreading)
BeitragVerfasst: Fr Apr 19, 2013 15:52 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Nov 30, 2011 21:41
Beiträge: 136
Wohnort: Bad Vilbel
Programmiersprache: Delphi 7
Hallo allerseits,
Ich bin immoment irgendwie total am verzweifeln mit Multithreading. Hab mir das Tutorial von Lossy ex und was ich sonst noch so im Internet finden konnte durchgelesen, aber mir hat bisher nix weiterhelfen können :(

Ich will eigentlich nicht mehr machen als an einer Stelle 2 Threads gleichzeitig laufen zu lassen.
Meine Idee war folgende:
-VCL Thread kommt an eine gewisse Stelle
-VCL Thread startet einen weiteren Thread.
-VCL Thread und weiterer Thread berechnen das nötige.
-VCL Thread soll warten bis anderer Thread fertig ist.
-VCL Thread soll fortfahren.
[...]
-VCL Thread zeichnet via OpenGL alles
[...]
-VCL Frameende.

Über OnIdle sollen diese Schritte dann wiederholt. Meine Codeumsetzung hat stark variiert, daher hier mein momentaner Code-Zustand:

Code:
  1. constructor TDCMatch.Create();
  2. begin
  3. inherited Create;
  4. Player := TDCPlayer.Create(meSetByteColor(16,16,255,255));
  5. Player.ListOfSpawner.Add(TDCSpawner.Create(DefaultPlayerStart, Player));
  6. Enemy := TDCPlayer.Create(meSetByteColor(255,16,16,255));
  7. Enemy.ListOfSpawner.Add(TDCSpawner.Create(DefaultEnemyStart, Enemy));
  8.  
  9. mtThreadCriticalSection := TCriticalSection.Create();
  10.  
  11. mtPlayerZeroCollisionEvent := TEvent.Create(nil, true, false, 'PlayerZeroCollisionEvent');
  12. mtPlayerOneCollisionEvent := TEvent.Create(nil, true, false, 'PlayerOneCollisionEvent');
  13.  
  14. mtPlayerZeroCollisionThread := TPlayerZeroCollisionThread.Create(false);
  15. mtPlayerZeroCollisionThread.FreeOnTerminate := true;
  16.  
  17. mtPlayerOneCollisionThread := TPlayerOneCollisionThread.Create(false);
  18. mtPlayerOneCollisionThread.FreeOnTerminate := true;
  19. end;
  20.  
  21. procedure TDCMatch.mtCollisions();
  22. var q: boolean;
  23. begin
  24. // Hier soll Multithreading gestartet werden
  25. mtPlayerZeroCollisionEvent.SetEvent();
  26. PlayerOneCollision(); // Aufwendige Funktion die parallell ausgeführt werden soll.
  27. // mtThreadCount zeigt die Anzahl der Threads auf die gewartet werden muss.
  28. mtThreadCount := 1;
  29. repeat
  30. mtThreadCriticalSection.Acquire;
  31.   try
  32.   q := (mtThreadCount = 0);
  33.   finally
  34. mtThreadCriticalSection.Release;
  35. Sleep(1);
  36.   end;
  37. until q; // warten bis alle Threads (immoment nur einer) ihre Arbeit beendet haben.
  38. end;
  39.  
  40. procedure TPlayerOneCollisionThread.sFinish;
  41. begin
  42. // mtThreadCount soll um 1 verringert werden.
  43. mtThreadCriticalSection.Acquire;
  44. try
  45.   mtThreadCount := mtThreadCount - 1;
  46. finally
  47.   mtThreadCriticalSection.Release;
  48. end;
  49. end;
  50.  
  51. procedure TPlayerZeroCollisionThread.Execute();
  52. begin
  53. while (not Terminated) do begin
  54.   if (mtPlayerZeroCollisionEvent.WaitFor(100) = wrSignaled) then begin
  55.     TheMatch.PlayerZeroCollision(); // Aufwendige Funktion (TheMatch ist die einzige Instanz von TDCMatch)
  56.     sFinish(); // Soll zeigen das er fertig ist.
  57.   end;
  58. end;
  59. end;


Habe das Spiel schon ohne Multithreading schon erfolgreich ausgeführt, liegt also nicht an Fehlern in den Funktionen.

Noch eine zusätzliche Frage, weswegen das wahrscheinlich auch nicht funktioniert: Wenn ein Thread am Ende von Execute ankommt, startet er dann von vorne, ist er terminated oder was passiert dann genau?

Danke schonmal im vorraus.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: HILFE! (Multithreading)
BeitragVerfasst: Fr Apr 19, 2013 16:52 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Apr 13, 2011 22:05
Beiträge: 218
Programmiersprache: Lazarus/FPC
Ich hab mal Multithreading bei einem Spiel zum Texturen nachladen genommen. Ich habs so gelöst:
Am Ende der EXECUTE-Methode kommt der Befehl

Code:
  1.  
  2.   Synchronize(GetResult);
  3.  


Und GetResult war eine Funktion in der Threadklasse die das Ergebnis in eine globale Variable der VLC-Unit geschrieben hat.

Du musst halt bei der Implementierung eine uses-Klausel hinzufügen das der Thread auf die VLC-Daten zugreifen kann.
Beispiel:
Code:
  1.  
  2. implementation
  3.  
  4. uses unit1;
  5.  
  6. Execute-Methode....GetResult...ect!
  7.  



Dort wo du in deinem Code Multithreadnig starten willst deklarierst du einfach eine Variable und rufst den Konstruktor auf:

Code:
  1.  
  2. var
  3.   Thread: TTestThread;
  4. begin
  5.   Thread := TTestThread.create(False);
  6.  

_________________
Ich teile manchmal heimlich durch Null. - Alber Einstein


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: HILFE! (Multithreading)
BeitragVerfasst: Fr Apr 19, 2013 17:08 
Offline
DGL Member
Benutzeravatar

Registriert: Sa Aug 18, 2007 18:47
Beiträge: 694
Wohnort: Köln
Programmiersprache: Java
Ist zwar jetzt nicht die Lösung deines Problems, aber eigentlich brauchst du für dieses Problem gar kein Multithreading, wenn der VCL Thread sowieso auf den anderen Thread wartet bis dieser fertig ist. Dann kann die Arbeit auch im VCL Thread gemacht werden.
Zitat:
-VCL Thread soll warten bis anderer Thread fertig ist.

_________________
Es werde Licht.
glEnable(GL_LIGHTING);
Und es ward Licht.


Zitat aus einem Java Buch: "C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off"

on error goto next


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: HILFE! (Multithreading)
BeitragVerfasst: Fr Apr 19, 2013 17:25 
Offline
Ernährungsberater
Benutzeravatar

Registriert: Sa Jan 01, 2005 17:11
Beiträge: 2067
Programmiersprache: C++
Knittel hat geschrieben:
Noch eine zusätzliche Frage, weswegen das wahrscheinlich auch nicht funktioniert: Wenn ein Thread am Ende von Execute ankommt, startet er dann von vorne, ist er terminated oder was passiert dann genau?

Der Thread ist terminated, da du noch das Flag für die automatische Freigabe gesetzt hast, wird auch automatisch sein Speicher freigegeben. Das ist daher also nur zu empfehlen, wenn der Thread selber keine Daten speichert sondern sie (synchronisiert) woanders speichert.

_________________
Steppity,steppity,step,step,step! :twisted:
❆ ❄ ❄ ❄ ❅ ❄ ❆ ❄ ❅ ❄ ❅ ❄ ❅ ❄ ❄
❄ ❄ ❄ ❅ ❄ ❄ ❄ ❅ ❄ ❄ ❆ ❄ ❄


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: HILFE! (Multithreading)
BeitragVerfasst: Fr Apr 19, 2013 17:33 
Offline
DGL Member

Registriert: Mo Nov 09, 2009 12:01
Beiträge: 200
http://code.google.com/p/omnithreadlibrary/


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: HILFE! (Multithreading)
BeitragVerfasst: Fr Apr 19, 2013 17:50 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Nov 30, 2011 21:41
Beiträge: 136
Wohnort: Bad Vilbel
Programmiersprache: Delphi 7
Erstmal danke für die ganzen Antworten, aber ich bin mir immernoch nicht ganz sicher, wie die Lösung jetzt aussehen soll.

Zitat:
Ist zwar jetzt nicht die Lösung deines Problems, aber eigentlich brauchst du für dieses Problem gar kein Multithreading, wenn der VCL Thread sowieso auf den anderen Thread wartet bis dieser fertig ist. Dann kann die Arbeit auch im VCL Thread gemacht werden.


Es kommt ja zwischen VCL-Thread startet den anderen Thread und VCL-Thread wartet auf den anderen Thread noch eine aufwendige Berechnungen, bzw. In meiner Anwendung gibt es 2 aufwendige Prozeduren. Der VCL-Thread startet den 2ten Thread. VCL-Thread arbeitet eine Prozedur ab der andere Thread die andere Prozedur. Da mit den Ergebnissen der Prozeduren danach weitergerechnet werden soll, soll hier der VCL-Thread (wenn nötig) auf Thread 2 warten.

Zitat:
Dort wo du in deinem Code Multithreadnig starten willst deklarierst du einfach eine Variable und rufst den Konstruktor auf:


das heißt, ich muss in jedem Frame den Thread neu erstellen? Und dann jedes mal mit FreeOnTerminate = true?

Zitat:
Der Thread ist terminated, da du noch das Flag für die automatische Freigabe gesetzt hast, wird auch automatisch sein Speicher freigegeben. Das ist daher also nur zu empfehlen, wenn der Thread selber keine Daten speichert sondern sie (synchronisiert) woanders speichert.


OK. Das hilft mir auch schonmal gut weiter :) Ich probier noch ein wenig rum, würde mich aber noch über weitere Ratschläge freuen.

EDIT: OK. Habs jetzt in einer "Sonderform" zum laufen gebracht.

Code:
  1. procedure TDCMatch.mtCollisions();
  2. var q: boolean;
  3. begin
  4. mtPlayerZeroCollisionThread := TPlayerZeroCollisionThread.Create(false);
  5. mtPlayerZeroCollisionThread.FreeOnTerminate := true;
  6. mtThreadCount := 1;
  7. repeat
  8. mtThreadCriticalSection.Acquire;
  9.   try
  10.   q := (mtThreadCount = 0);
  11.   finally
  12. mtThreadCriticalSection.Release;
  13. Sleep(1);
  14.   end;
  15. until q;
  16. PlayerOneCollision();
  17. end;
  18.  
  19. procedure TPlayerZeroCollisionThread.Execute();
  20. begin
  21. TheMatch.PlayerZeroCollision();
  22. sFinish();
  23. end;
  24.  
  25. procedure TPlayerZeroCollisionThread.sFinish();
  26. begin
  27. mtThreadCriticalSection.Acquire;
  28. try
  29.   mtThreadCount := mtThreadCount - 1;
  30. finally
  31.   mtThreadCriticalSection.Release;
  32. end;
  33. end;


Immoment, das ist mir klar, werden die Berechnungen nacheinander ausgeführt, habe ich allerdings testweise mal eingebaut um zu schauen wo das Problem liegt. Sobald ich PlayerOneCollision(); vor dem warten auf den 2ten Thread einfüge, gibt es einen Deadlock (spätestens nach 1 sekunde). Ist da vielleicht noch ein Problem mit der Critical Section? Ich dachte, der 2te Thread kann rein, sboald ihn der erste verlassen hat (er ist sozusagen in der Warteschlange), oder irre ich mich da wieder?

Sicherheitshalber nochmal der Code der in den beiden Threads ausgeführt wird.
1. Überprüft Kollision von Spieler 1en mit Computer 0en
2. Überprüft Kollision von Spieler 0en mit Computer 1en
Da ja somit komplett auf unterschiedliche Objekte zugegriffen wird, dachte ich, dass man diese Aufgaben parallell ausführen kann.
Code:
  1. procedure TDCMatch.PlayerZeroCollision();
  2. var i, j: integer; QLife: single;
  3. begin
  4. if (Player.ListOfZero.Count > 0) and (Enemy.ListOfOne.Count > 0) then
  5.   for i:= 0 To Player.ListOfZero.Count - 1 do
  6.     for j:= 0 To Enemy.ListOfOne.Count - 1 do
  7.       if (ABS(TDCBit(Player.ListOfZero[i]).Position.X - TDCBit(Enemy.ListOfOne[j]).Position.X) <
  8.           (TDCBit(Player.ListOfZero[i]).Life + TDCBit(Enemy.ListOfOne[j]).Life) * 0.5) then
  9.         if (ABS(TDCBit(Player.ListOfZero[i]).Position.Y - TDCBit(Enemy.ListOfOne[j]).Position.Y) <
  10.           (TDCBit(Player.ListOfZero[i]).Life + TDCBit(Enemy.ListOfOne[j]).Life) * 0.5) then
  11.           begin
  12.           QLife := TDCBit(Player.ListOfZero[i]).Life;
  13.           TDCBit(Player.ListOfZero[i]).Damage(TDCBit(Enemy.ListOfOne[j]).Life);
  14.           TDCBit(Enemy.ListOfOne[j]).Damage(QLife);
  15.           end;
  16. end;
  17.  
  18. procedure TDCMatch.PlayerOneCollision();
  19. var i, j: integer; QLife: single;
  20. begin
  21. if (Player.ListOfOne.Count > 0) and (Enemy.ListOfZero.Count > 0) then
  22.   for i:= 0 To Player.ListOfOne.Count - 1 do
  23.     for j:= 0 To Enemy.ListOfZero.Count - 1 do
  24.       if (ABS(TDCBit(Player.ListOfOne[i]).Position.X - TDCBit(Enemy.ListOfZero[j]).Position.X) <
  25.           (TDCBit(Player.ListOfOne[i]).Life + TDCBit(Enemy.ListOfZero[j]).Life) * 0.5) then
  26.         if (ABS(TDCBit(Player.ListOfOne[i]).Position.Y - TDCBit(Enemy.ListOfZero[j]).Position.Y) <
  27.           (TDCBit(Player.ListOfOne[i]).Life + TDCBit(Enemy.ListOfZero[j]).Life) * 0.5) then
  28.           begin
  29.           QLife := TDCBit(Player.ListOfOne[i]).Life;
  30.           TDCBit(Player.ListOfOne[i]).Damage(TDCBit(Enemy.ListOfZero[j]).Life);
  31.           TDCBit(Enemy.ListOfZero[j]).Damage(QLife);
  32.           end;
  33. end;


P.S. sorry für die spärliche bzw. nicht vorhandene Kommentarausstattung :/


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: HILFE! (Multithreading)
BeitragVerfasst: Sa Apr 20, 2013 11:19 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Ganz allgemein würde ich dir empfehlen, dir mal das Konzept von Semaphoren zu gemüte zu führen. Das würde dir das Erzeugen/Löschen sparen und du kannst dem Thread einfach ein Startsignal geben, wenn's so weit ist. Ebenso kann der Thread so sauber zurückgeben, dass er fertig ist.

Ansonsten erscheint mir das Konzept sinnig, so ähnlich mache ich es mit ManiacLab ja auch. Woran erkennst du den Deadlock, wenn er auftritt? Kannst du mal im Debugger nachschauen, wo die Threads dann warten?

grüße

ps.: Solltest du wider Erwarten unter Linux unterwegs sein ist helgrind das Mittel der Wahl, um des Problem zu untersuchen.

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: HILFE! (Multithreading)
BeitragVerfasst: Sa Apr 20, 2013 12:45 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Nov 30, 2011 21:41
Beiträge: 136
Wohnort: Bad Vilbel
Programmiersprache: Delphi 7
Hallo nochmal.

Das Problem war deutlich einfacher als erwartet und ein großer Denkfehler bei mir:

Code:
  1. procedure TDCMatch.mtCollisions();
  2. var q: boolean;
  3. begin
  4. mtThreadCount := 1;
  5. mtPlayerZeroCollisionThread := TPlayerZeroCollisionThread.Create(false);
  6. mtPlayerZeroCollisionThread.FreeOnTerminate := true;
  7. PlayerOneCollision();
  8. repeat
  9. mtThreadCriticalSection.Acquire;
  10.   try
  11.   q := (mtThreadCount <= 0);
  12.   finally
  13. mtThreadCriticalSection.Release;
  14. Sleep(1);
  15.   end;
  16. until q;
  17. end;


Das Problem war, dass ich die Variable mtThreadCount erst gesetzt habe, nachdem ich den anderen Thread erzeugt habe (hier sogar noch nach PlayerOneCollision) und somit der Thread manchmal fertig war bevor mtThreadCount = 1 gesetzt wurde. Da der Thread danach fertig war blieb mtThreadCount die ganze Zeit 1 und die Anwendung blieb stehen.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: HILFE! (Multithreading)
BeitragVerfasst: Sa Apr 20, 2013 20:11 
Offline
DGL Member

Registriert: Fr Okt 03, 2008 13:32
Beiträge: 367
Wieso benutzt du nicht einfach TThread.WaitFor?
FreeOnTerminate muss dann allerdings false sein, sonst würde man u.U. auf eine nicht mehr existierende Instanz zugreifen. Außerdem muss man die Instanz danach dann natürlich auch selbst freigeben.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: HILFE! (Multithreading)
BeitragVerfasst: Mi Apr 24, 2013 19:10 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Nov 30, 2011 21:41
Beiträge: 136
Wohnort: Bad Vilbel
Programmiersprache: Delphi 7
WaitFor hatte bei mir irgendwie nicht richtig funktioniert (vermutlich weil ich es falsch angewandt habe), aber ich hab sowieso vor, das nochmal zu überarbeiten, bzw. ne eigene Threadklasse drüber zu schreiben um die ganze Angelegenheit ein wenig zu vereinfachen.


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: Majestic-12 [Bot] und 6 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:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.011s | 15 Queries | GZIP : On ]