Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi THREADS: Anzahl der gerade aktiven Threads (https://www.delphipraxis.net/3950-threads-anzahl-der-gerade-aktiven-threads.html)

APP 8. Apr 2003 10:23


THREADS: Anzahl der gerade aktiven Threads
 
Hallo,
ich erzeuge in Abhängigkeit der Anzahl der Einträge einer ListBox Treads der selben Klasse:
Delphi-Quellcode:
BEGIN
  FOR i := 0 TO ListBox1.Items.Count - 1 DO
    BEGIN
      ...
      TFlappPrintThread.Create(ListBox1.Items.Strings[i], i, ListBox1);
    END;
END;
Da diese Printjobs unterschiedlich lange dauern, möchte ich wissen wieviele Threads gerade aktiv sind, da ich max. 16 Threads zugleich zulassen möchte.
Gibt es die Möglichkeit die Anzahl aktiven Threads abzufragen, oder muß ich mir selbst eine Art Stack basteln?

p.s. Die Threads werden nach Beendigung sofort zerstört, so wie es mir
Christian Seehase in einem Anderen Beitrag gezeigt hat.)

Luckie 8. Apr 2003 10:42

Zähl doch einfach mit einer globalen Variable mit. Beim Erstellen erhöhen und beim Beenden erniedrigen.

Motzi 8. Apr 2003 11:52

Ergänzung: das Erhöhen und Erniedrigen muss aber atomar durchgeführt werden! Schau dir dazu die Interlock*-Funktionen an...

APP 8. Apr 2003 12:44

Danke @Motzi und @Luckie,

aber ich komme mit den Threads und Eueren Tips nicht klar :cry: (bin noch Thread-Anfänger)

Ich übergebe iNumberOfThreads beim 1. Aufruf in meiner Form1-Unit mit:
Delphi-Quellcode:
    iNumberOfThreads := 0;
    FOR i := 0 TO ListBox1.Items.Count - 1 DO    //Maximal 16 THREADS zugleich!!!
      BEGIN
      ...
         TFlappPrintThread.Create(sFile, i, ListBox1, iNumberOfThreads);
     ...
     END;
    ...
  WHILE CloseIt DO
    BEGIN
      Application.ProcessMessages;
      Label1.Caption := IntToStr(iNumberOfThreads); // HIER SOLLTE DIE ANZAHL DER OFFENEN THREADS STEHEN -ist aber immer Null :-((
      Application.ProcessMessages;
      Form1.Refresh;
      Application.ProcessMessages;
    END;
in meiner Thread-Unit mache ich dann das:
Delphi-Quellcode:
CONSTRUCTOR TFlappPrintThread.Create(CONST aFile: STRING; CONST aThreadID: Integer; aListBox: TListBox; iNumberOfThreads: Integer);
BEGIN
  FaListbox := aListBox;
  FaThreadID := aThreadID;
  FiNumberOfThreads := iNumberOfThreads;
  FaFile := aFile;
  FreeOnTerminate := true;                       // Thread freigeben, wenn beendet
  INHERITED Create(false);                       // False = sofort starten
END;
Delphi-Quellcode:
PROCEDURE TFlappPrintThread.Execute;
VAR
  ShExecInfo                 : TShellExecuteInfo;
BEGIN
  InterlockedIncrement(FiNumberOfThreads); // INTERLOCK++
  TRY
    IF NOT FileExists(FaFile) THEN
      BEGIN
        MessageDlg('File: ' + FaFile + ' not found', mtError, [mbOk], 0);
      END;
    FillChar(ShExecInfo, SizeOf(ShExecInfo), 0);
    WITH ShExecInfo DO
      BEGIN
        cbSize := SizeOf(ShExecInfo);
        fMask := SEE_MASK_NOCLOSEPROCESS;        //  SEE_MASK_NOCLOSEPROCESS OR SEE_MASK_FLAG_DDEWAIT;
        lpFile := PChar(FaFile);
        lpVerb := 'print';
        nShow := SW_HIDE;                        //SW_SHOW;
      END;
    IF ShellExecuteEx(@ShExecInfo) THEN
      BEGIN
        WaitForSingleObject(ShExecInfo.hProcess, INFINITE); //0
    Synchronize(SyncListbox);
    InterlockedDecrement(FiNumberOfThreads); // INTERLOCK--
      END
    ELSE
      ShowMessage('Fehler beim Öffnen');
  FINALLY
    Terminate;                                   // dann beenden
  END;
END;

oki 8. Apr 2003 14:18

Hi,

ich hab schon mal gleiches Problem bearbeitet und folgenden Lösungsansatz gewählt.

Mein Thread beinhaltet ein Property vom Typ TNitifyEvent. Beim Terminieren des Threads rufe ich dieses Ereignis auf und meine Hauptanwendung bekommt die entsprechende Mitteilung. Ob dann ein Counter oder etwas anderes bearbeitet wird bleibt Dir überlassen.

Delphi-Quellcode:
type
  TMapThread = class(TThread)
  private
    { Private-Deklarationen }
    FIsSetObj                : Boolean;
    FIsSetCon                : Boolean;
    FOnFinish                : TNotifyEvent;
  protected
    procedure ExecuTMapte; override;
  public
    property IsSetObject : Boolean read FIsSetObj write FIsSetObj;
    property IsSetCon : Boolean read FIsSetCon write FIsSetCon;
    property OnFinish : TNotifyEvent read FOnFinish write FOnFinish;
Wenn der Thread beendet wird rufe ich das Ereignis auf
Delphi-Quellcode:
If Assigned(FOnFinish) then FOnFinish(self);
In der Hauptanwendung wird nach dem Creieren des Thread die Ereignis-Procedure zugewiesen und in dieser entsprechend reagiert.

MyThread := TMapThread.Create(True);
OnFinish := OnThreadFinish;


TMain.OnThreadFinish(Sender : TObject);
begin
dec(mein_globaler_Threadcounter);
end;
[delphi]

APP 8. Apr 2003 15:17

@oki,

Vielen Dank, es funktioniert!! :dancer: :dancer2:



p.s. Eine kleine Frage noch (wie gesagt ich bin kein Thread-Profi):
Ist dieser Code auch "Thread-Save", ich meine damit, was passiert in
Delphi-Quellcode:
TMain.OnThreadFinish(Sender : TObject);
wenn mehrere Threads zugleich dieses Ereignis anstoßen (Stichwort: Synchronize)?

oki 8. Apr 2003 15:35

Hi,

ich rufe das OnFinisch-Ereignis aus dem Thread in einer eigenen Thread-Methode auf. Dort werden noch andere Sachen bearbeitet. Diese Methode rufe ich aus Execute mit Syncronize auf. Bis dato habe ich mit den Ereignissen keine Probleme gehabt. Es benutzen bei mir auch alle Threads die gleiche Ereignisbehandlungsroutine des Main-Fensters. Ob es da aber Probleme geben kann bin ich mir nicht hundert prozentig sicher. Ich würde aber sagen, da die Ereignisbehandlung über die Botschaftsschlange von Windows läuft dürfte nichts passieren.

Zusätzlich mache ich bei mir noch folgendes. Ich merke mir beim kreieren die Thread-Handle in einer Liste. Über den Parameter Sender bekomme ich heraus welcher Thread sich gerade beendet hat.

Ich hoffe, das hat geholfen.

Gruß oki

Motzi 8. Apr 2003 16:45

Zitat:

Zitat von oki
Delphi-Quellcode:
TMain.OnThreadFinish(Sender : TObject);
begin
dec(mein_globaler_Threadcounter);
end;

Genau das meinte ich... das dekriminieren des ThreadCounters sollte atomar erfolgen, damit nicht möglicherweise 2 Threads gleichzeitig(!) auf die Variable zugreifen können!


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:05 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz