Entwickler-Ecke

Windows API - mehrere Threads sollen Daten der Reihe nach abarbeiten


Bergmann89 - Mo 14.03.11 19:36
Titel: mehrere Threads sollen Daten der Reihe nach abarbeiten
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.


jaenicke - Mo 14.03.11 21:11

user profile iconBergmann89 hat folgendes geschrieben Zum zitierten Posting springen:
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 - Mo 14.03.11 22: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.


Bergmann89 - Di 15.03.11 22: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):

Delphi-Quelltext
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  
          {rechne was}
          Finished := True;
        end;
      end;
    else
      Finished := True;
      {Errorhandling...}
    end;
  finally
    if not ReleaseSemaphore(fSemaphor, 1nilthen begin
      Finished := True;
      {Errorhandling...}
    end;  
  end;
  if not Finished then begin
    ResetEvent(fWaitEvent);
    if WaitForSingleObject(fWaitEvent, INFINITE) <> WAIT_OBJECT_0 then begin
      Finished := True;
      {Errorhandling...}
    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.