Einzelnen Beitrag anzeigen

alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 

Re: Probleme mit Threads und Aufgaben-Pool

  Alt 19. Mai 2005, 15:59
Natürlich habe ich eine andere Idee. Die müsste auch 'besser' sein.
Hintergrund sind 'Semaphoren'. Eigentlich ist so eine Semaphore nix anderes als ein threadsicherer Zähler mit dem man Threads steuert.
Es gibt 4 Windows-API Prozeduren, die hier von Bedeutung sind:
CreateSemaphore erzeugt eine Semaphore mit einem definierten Anfangszustand
ReleaseSemaphore erhöht den Wert um eins,
WaitForSingleObject wartet, bis die Semaphore <>0 ist (und verringert sie dann sofort um 1) und
CloseHandle gibt das Handle wieder an Windows zurück.

Die Idee ist folgende:
Am Anfang ist die Semaphore = 0. Wenn ein Job per AddJob in die Liste kommt, wird die Semphore um eins erhöht.
So weit, so gut. Alle Threads warten nun, bis die Semaphore <> 0 ist und verringern die Semaphore um 1, wenn das der Fall ist. Das ist wichtig. Angenommen, zwei Threads warten auf die Semaphore. Genau 1 Job wird in die Jobliste gepackt, ergo ist die Semaphore=1. Aber: Nur ein Thread (welcher, wissen wir nicht), wird die Nachricht bekommen, das die Semaphore <>0 ist. Der andere Thread kriegt davon nix mit!

Du musst eigentlich nur Folgendes machen:
1. Die TJobList bekommt eine Property "Semaphore : THandle read fHandle".
2. TJobList.Create erzeugt eine Semaphore mit "fHandle := CreateSemaphore (nil,0,32767,nil)". Ich denke, 32767 offene Jobs sollten reichen.
3. TJobList.GetNextJob liefert '' zurück, wenn die Liste leer ist (hatte ich vergessen).
4. TJobList.Destroy gibt das fHandle mit "CloseHandle (fHandle)" wieder frei.
5. Die Execute-Methode der Threads sieht nun so aus:
Delphi-Quellcode:
Procedure TMyThread.Execute;
Begin
  While Not Terminated do
    If WaitForSingleObject (aJobList.Semaphore, ccMyThreadTimeout) Then Begin
      aJob := aJobList.GetNextJob;
      if aJob<>'Then
        DoExecuteJob (aJob);
      End
End;
ccMyThreadTimeout setzt Du so auf 500 Millisecs. Du kannst auch INFINITE hinschreiben, dann warten sie wirklich *BIS* was zu tun ist, leider bekommst du dann Probleme, sie zu terminieren. Deshalb also dieses Timeout.

Prinzipiell kein Unterschied zu Deiner 'Sleep' Geschichte. WaitForSingleObjects ist aber laut Microsoft der bessere Weg, weil die CPU-Belastung minimal wird. Du kannst das Thread-timeout hochsetzen, wenn dein Programm immer läuft.

**** Nach einer Nacht drüber schlafen, bin ich heute auch etwas schlauer. Natürlich kann man die Threads endlos warten lassen. Dazu muss beim Programmende nur die Semaphore sehr hoch gezählt werden (so hoch wie es threads gibt). Schau Dir die FormDestroy-Methode einfach an...

Bei Deiner Idee, im Hauptprogramm immer mal wieder zu schauen, ob was zu tun ist (um dann die Jobliste zu füllen), kann ich Dir nicht speziell helfen, weil ich nicht weiss, was da genau los ist. Aber, prinzipiell würde ich mich an Deiner Stelle mit den Sempahoren beschäftigen.

Hier ist mein Beispiel-Projekt.
Angehängte Dateien
Dateityp: zip threadsandjobs_127.zip (2,0 KB, 169x aufgerufen)
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat