Entwickler-Ecke

Windows API - Thread-Synchronisation, zuverlässige Realisierung


GuaAck - Do 15.05.14 22:47
Titel: Thread-Synchronisation, zuverlässige Realisierung
Liebe Experten,

ich möchte eine umfangreiche Rechenaufgabe auf viele Kerne einer CPU verteilen, also mache ich mehrere Threads.

Bsp.: Ich suche die "schönste" (wie auch immer) Zahl im Bereich 1... 1 Million, also teile ich das in 1000er-Pakete. Ich starte Thread 1 für 1..1000, dann Thread 2 für 1001..2000 usw.

Jetzt kommt das Problem: Wenn alle Threads beschäftigt sind, dann muss der organisierede Thread warten. Nehme ich "waitfor" auf Event, Mutex, Semaphore. Mein Problem liegt in den Rechen-Threads: Der sieht ja etwa so aus:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
Procedure Excecute;
REPEAT
  Suche_schönste_Zahl_im Bereich;
  Setze Event/Mutex/Semaphore;
  suspend;
UNTIL ewig; {klar, Terminated usw. wird abgefragt}
END;


NUN: Was passiert, wenn zwischen "Setze Event/Mutex/Semaphore" und "suspend" ein Threadwechsel erfolgt? Der übergeordnete organisierende Thread erwacht aus seinem "waitfor", findet aber keinen Thread, der "suspended" ist. Selbst wenn ich eine eigene Variable einrichte und abfrage, dann würde ja das Resume ins Leere laufen.

Klar, mir fallen work-arounds ein, aber das muss doch vom Ansatz her besser gehen. In den reichlich verfügbaren Texten im Internet habe ich nichts zu dieser Frage finden können.

Aber vielleicht ist ja auch mein Ansatz vollkommen falsch???? Evtl. besser den Thread terminieren und jeweils neu starten??? Oder gibt es außer Event, Mutex, Semaphore bessere Alternativen???
Im Prinzip sind solche Aufgagen heute bei Multi-Core-Anwendungen für aktuelle Prozessoren doch dauernd zu lösen. Somit hoffe ich auf Tipps und Links auf entsprechende Seiten.

Beste Grüße GuaAck

Moderiert von user profile iconMartok: Delphi-Tags hinzugefügt


Sinspin - Fr 16.05.14 00:56

Warum beendest du den knusper Thread nicht einfach wenn er fertig ist? Warum suspendieren und Speicher/Systemressourcen blockieren? Zudem ist suspended in neueren Version von Delphi als veraltet markiert.
Vor dem Beenden sendest du dann ein Event das dem Hauptthread sagt das wieder Platz auf der CPU ist und weitere arbeit vergeben werden kann.
Oder du verwendest TCriticalSection um eine globale Bariable hoch oder runter zu zählen. Die wird dann im Haupttread überwacht und neue abeit erzeugt. Mit TCriticalSection ist es auch möglich die Ergebnisse in eine globale Liste zu schreiben ohne das ein anderer Thread in die Quere kommen kann. Allerdings kann das zum Flaschenhals werden wenn die Arbeitsthreads zu schnell fertig sind. Da sie ihre Daten ja nur einer nach dem anderen schreiben können.


jaenicke - Fr 16.05.14 07:33

Das Stichwort ist Threadpool, da gibt es auch schon fertige Implementierungen, eine umfangreiche z.B. drüben in der Delphipraxis. Ich muss los, deshalb kann ich grad nicht mehr schreiben.


Martok - Fr 16.05.14 18:53

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Das Stichwort ist Threadpool, da gibt es auch schon fertige Implementierungen, eine umfangreiche z.B. drüben in der Delphipraxis. Ich muss los, deshalb kann ich grad nicht mehr schreiben.
Ich arbeite z.B. sehr gern mit der mittlerweile eingestellten AsyncCall [http://andy.jgknet.de/blog/bugfix-units/asynccalls-29-asynchronous-function-calls/] (da ist das gradezu trivial, da du eine lokale bzw anonyme Prozedur für die Berechnung nehmen kannst), die OmniThreadLibrary taucht auch immer mal wieder auf (für die sind aber meine Delphis zu alt).