| Autor |
Beitrag |
Bergmann89
      
Beiträge: 1742
Erhaltene Danke: 72
Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
|
Verfasst: Mo 14.03.11 18:36
Hey,
ich steh mal wieder vor einem Problem bei der Thread-Synchronisierung, wo ich nicht recht weiter weiß. Meine Threads bekommen einen Satz Daten und den Listen-Index dieser Daten. Die Daten müssen jetzt der Reihe nach durch 5 verschiedene Routinen. Die Routinen wissen den Index des Datensatzes der als nächstes bearbeitet werden soll. Die Daten sollen aufsteigen von 0 bis n-1 verarbeitet werden. Jetzt müssen die Threads aber auch bestimmte Regeln befolgen:
1. Betritt keine Routine, die bereits von einem anderen Thread ausgeführt wird (kein Problem da nehm ich CriticalSections, Mutex oder Semaphor)
2. Betritt keine Routine, wenn der Index deiner Daten größer als der aktuell zu bearbeitende Index ist (und hier weiß ich nicht ganz weiter)
Die einzige Idee, die ich hab ist folgende: Ich mach ne Schleife über alle Routinen. Routinen, die bereits erfolgreich ausgeführt wurden werden übersprungen. Die Schleife wird erst beendet, wenn der Thread alle Routinen abgearbeitet hat. Mit der Methode verschenk ich aber Rechenleistung und das gefällt mir nicht wirklich. Ich such jetzt irgendwie nach ner Möglichkeit den Thread zu pausieren, bis seine Daten an der Reihe sind berechnet zu werden. Hat da jmd ne Idee?
€: die Threads kennen sich untereinander nicht, also kann ich da auch meine Events oder sowas benutzten bzw. mit fällt jetzt nicht ein wie ich die sinnvoll nutzen könnte...
MfG & Thx Bergmann.
_________________ Ich weiß nicht viel, lern aber dafür umso schneller^^
|
|
jaenicke
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mo 14.03.11 20:11
Bergmann89 hat folgendes geschrieben : | | Ich such jetzt irgendwie nach ner Möglichkeit den Thread zu pausieren, bis seine Daten an der Reihe sind berechnet zu werden. Hat da jmd ne Idee? |
Erzeuge mit CreateEvent ein Event und warte darauf mit WaitForMultipleObjects.
Dann kannst du das Event mit SetEvent auslösen. Das funktioniert auch mit Threads.
|
|
Bergmann89 
      
Beiträge: 1742
Erhaltene Danke: 72
Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
|
Verfasst: Mo 14.03.11 21:08
Hey,
mit dem Gedanken habe ich ja auch schon gespielt, aber da kommt ich auch nich weiter. Bsp:
Thread 1 mit ID = 0
Thread 2 mit ID = 1
Thread 3 mit ID = 2
die Routine erwaret Daten mit ID = 0
Thread 2 will in die Routine, hat nicht die richtige ID, also wartet er auf sein Event.
Thread 3 will in die Routine, hat nicht die richtige ID, also wartet er auch auf sein Event.
Thread 1 will in die Routine, hat die richtige ID, arbeitet alles ab... Un nun? Wenn jeder Thread das Event selbst besitzt und als Methode oder Eigenschaft zur verfügung stellt, dann weiß Thread 1 nicht welchen Thread er ansprechen soll, weil sich die Threads untereinander nicht kennen. Wenn ich die Events in der Routine speicher, dann müsste ich so ne Art Liste machen, oder ein Array mit je einem Event pro Thread. Aber das halte ich auch irgendwie für komisch
Vlt sollte ich die Aufgaben der Threads anderes verteilen und jedem Thread eine Kopie der Liste geben die er dann in einer Routine abarbeitet. Anstatt wie jetzt jeder Thread jede Routine mit einem Datensatz. Da müsste ich auch weniger synchronisieren.
MfG Bergmann.
_________________ Ich weiß nicht viel, lern aber dafür umso schneller^^
|
|
Bergmann89 
      
Beiträge: 1742
Erhaltene Danke: 72
Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
|
Verfasst: Di 15.03.11 21:25
Hey,
hab meine Denkblockade überwinden können, aber so ganz will es noch nicht funktionieren. Und zwar kommt es ab und zu zum Deadlock. Hier der Code (vereinfacht):
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32:
| Finished := False; repeat WaitResult := WaitForSingleObject(fSemaphor, SEMAPHORE_WAIT_TIME); try case WaitResult of WAIT_OBJECT_0: begin if Thread.DataID > fNextID then begin Finished := False end else begin Finished := True; end; end; else Finished := True; end; finally if not ReleaseSemaphore(fSemaphor, 1, nil) then begin Finished := True; end; end; if not Finished then begin ResetEvent(fWaitEvent); if WaitForSingleObject(fWaitEvent, INFINITE) <> WAIT_OBJECT_0 then begin Finished := True; end; end; until Finished; SetEvent(fWaitEvent); |
Ein Thread kommt in den Arbeitsbereich, und schützt als erstes den Zugriff auf den Bereich mit einem Semaphor. Dann guckt er ob er die benötigte DatenID hat. Wenn ja dann darf er weiter rechnen. Dann verlässt er den geschützen Bereich (gibt den Semaphor frei). Wenn er nicht die richtige ID hat, dann wartet er auf ein Event. Das wird jetzt solange wiederholt, bis die Routine soweit hinterher ist, dass die Daten des Threads an der Reihe sind. Sobald ein Thread die Routine verlässt ruft er das Event auf, um die wartenden Threads zu wecken, das diese erneut prüfen können, ob sie rechnen dürfen oder sich wieder schlafen legen sollen.
Ich find aber den Fehler nicht. Sieht jmd von euch, wo da der Deadlock enstehen kann?!
MfG Bergmann.
_________________ Ich weiß nicht viel, lern aber dafür umso schneller^^
|
|
|