Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi WaitForMultipleObjects funktioniert irgendwie nicht (https://www.delphipraxis.net/150540-waitformultipleobjects-funktioniert-irgendwie-nicht.html)

MicAlter 20. Apr 2010 11:56


WaitForMultipleObjects funktioniert irgendwie nicht
 
Hallo zusammen,

irgendwie funktioniert die SuFu nicht richtig... Suche nach "WaitForMultipleObjects" gibt kein Ergebnis zurück, obwohl ein solches Thema bereits existiert.

Ist aber nicht ganz mein Thema:

Ich möchte mehrere Worker-Threads für eine Suchfunktion benutzen und auf deren Ende warten. Jeder Thread liefert mir ein Ergebnis zurück welches ich auswerten möchte. Dafür ist, denke ich zumindest, die Funktion WaitForMultipleObjects gedacht.

Hier mein Code:
Delphi-Quellcode:

TMyThread.Constructor( nMaxLaufzeit : Integer; AMemo : TMemo );
begin
  inherited Create( True );
  FMaxLaufzeit := nMaxLaufzeit;
  FMemo := AMemo;
  FreeOnTerminate := True;
  Resume;
end;

TMyThread.ShowThreadStatus;
begin
  Memo.Lines.Add( Format('Alive from thread %d, %d of %d',[self.Handle,FCurrent,FMaxLaufzeit]) );
end;

TMyThread.Execute;
begin
  FCurrent := FMaxLaufzeit;
  while not Terminated do
  begin
    Sleep(1000);
    Synchronize(ShowThreadStatus);
    Dec( FCurrent );

    if FCurrent < 1 then
       Terminate;
  end;
end;


const MAX = 5;
var
   ThreadList : array[0..MAX-1] of TMyThread;
   ThreadHandles : array[0..MAX-1] of THandle;
   i,ThreadsRunning : Integer;
   dw,idx : DWord;

   //Threads erzeugen und Handle-Liste füllen
   for i := 0 to MAX-1 do
   begin
     //Max. Laufzeit des Threads in Sekunden mitgeben
     ThreadList[i] := TMyThread.Create( (i+1)*3 );
     ThreadHandles[i] := ThreadList[i].Handle;
   end;

   ThreadsRunning := MAX;
   while ThreadsRunning > 0 do
   begin
     //dw := WaitForMultipleObjects( MAX, @ThreadHandles, false, 0); //gleiches Ergebnis
     dw := WaitForMultipleObjects( MAX, @ThreadHandles[0], false, 0);

     if (dw <> WAIT_TIMEOUT) AND
        (dw <> WAIT_FAILED) then
     begin
       //Array-Index des auslösenden Threads errechnen
       idx := dw - WAIT_OBJECT_0;
       if idx < MAX then
       begin
         Memo.Lines.Add( Format('Thread %d (Handle:%d) beendet.',[idx,ThreadHandles[idx]]) );
         Dec( ThreadsRunning );
       end;      
     end;

     Application.ProcessMessages;
   end;
Die Threads geben nun ihre Statusmeldungen korrekt aus. So weit so gut.
Nun erwarte ich, dass ich für jeden Thread, der sich beendet ein "Signal" bekomme. Ist aber leider nicht so :wall:
Einmal bekomme ich ein "gültigen" Index (2), danach immer nur WAIT_FAILED?

Verstehe ich den Sinn der Funktion ncht richtig oder mache ich irgendwas falsch?

lg,
Michael

sirius 20. Apr 2010 12:12

Re: WaitForMultipleObjects funktioniert irgendwie nicht
 
Zum Fehler:
Nachdem der erste Thread beendet ist, übergibst du eine falsche Anzahl an Threadhandles inkl. eines ungültigen Handles an die Funktion. Du musst dein Array verkürzen bzw. umsortieren.

Allgemein: Schau dir mal MsgWaitforMultipleObjects an, damit du nicht ständig durch dein Programm rennst, sondern nur, wenn auch wirklich was passiert.

Zum Suchen:
Ich glaube in der DP war eine maximale Länge (20 Zeichen?) der Suchbegriffe ein Problem.
Nutze besser ref.dp200x !

MicAlter 20. Apr 2010 12:31

Re: WaitForMultipleObjects funktioniert irgendwie nicht
 
Hallo sirius,

hmmm... ich war gerade dabei das Array zu verkürzen, als ich Deine Nachricht gelesen habe :thumb: Und funktioniert... danke.

Delphi-Quellcode:
   var
   ThreadHandles : array of THandle;

   ...
   SetLength(ThreadHandles,MAX);
   ...

   ThreadsRunning := MAX;
   while ThreadsRunning > 0 do
   begin
     dw := WaitForMultipleObjects( ThreadsRunning, @ThreadHandles[0], false, 0);

     if (dw <> WAIT_TIMEOUT) AND
        (dw <> WAIT_FAILED) then
     begin
       //Array-Index des auslösenden Threads errechnen
       idx := dw - WAIT_OBJECT_0;
       if idx < MAX then
       begin
         Memo.Lines.Add( Format('Thread %d (Handle:%d) beendet.',[idx,ThreadHandles[idx]]) );

         Dec( ThreadsRunning );

         //Wenn nicht letztes Element signalisiert wurde, dann letztes Element dem Signalisiertem zuweisen
         if idx <> ThreadsRunning then
            ThreadHandles[idx] := ThreadHandles[ThreadsRunning];
         
         //Letztes Element abschneiden
         SetLength(ThreadHandles,ThreadsRunning);
       end;      
     end;

     Application.ProcessMessages;
   end;

Komisch finde ich, dass sich mein Thread gar nicht "richtig" meldet, wenn er aus dem Execute raus kommt. Ich bekomme das Signal nur, wenn ich am Ende explizit "TerminateThread" aufrufe - :gruebel: Noch'n Fehler?

Delphi-Quellcode:
TMyThread.Execute;
begin
  FCurrent := FMaxLaufzeit;
  while not Terminated do
  begin
    Sleep(1000);
    Synchronize(ShowThreadStatus);
    Dec( FCurrent );

    if FCurrent < 1 then
       Terminate;
  end;

  //Ansonsten wird das Thread-Ende nicht signalisiert!)
  TerminateThread( self.Handle, 0 );
end;



Ich habe MsgWaitForMultipleObjects bereits mir diversen Events erfolgreich getestet. Hing halt bei der obigen Variante fest... gleich mal weiter tippen.

Und die "ref.dp200x" kannte ich noch gar nicht... :cyclops:

sirius 20. Apr 2010 14:21

Re: WaitForMultipleObjects funktioniert irgendwie nicht
 
Zitat:

Zitat von MicAlter
Komisch finde ich, dass sich mein Thread gar nicht "richtig" meldet, wenn er aus dem Execute raus kommt. Ich bekomme das Signal nur, wenn ich am Ende explizit "TerminateThread" aufrufe - :gruebel: Noch'n Fehler?

Das kann ich mir auch nicht erklären. Der Thread meldet sich schon. Dazu muss man nicht extra terminateThread aufrufen. Es reicht schon aus der ThreadProc rauszulaufen. Außerdem ruft die VCL sowieso ExitThread auf (welche auch nur Terminatethread aufruft).

MicAlter 20. Apr 2010 15:34

Re: WaitForMultipleObjects funktioniert irgendwie nicht
 
Wahrscheinlich liegt es an der guten alten Delphi 5 Version, die hier so vor sich hinwerkelt :roll:

Dort wird (noch) kein Aufruf von ExitThread gemacht:

Delphi-Quellcode:
*****  Classes.pas ******
<--schnipp-->
destructor TThread.Destroy;
begin
  if not FFinished and not Suspended then
  begin
    Terminate;
    WaitFor;
  end;
  if FHandle <> 0 then CloseHandle(FHandle);
  inherited Destroy; //von TObject
  RemoveThread;
end;
<--schnapp-->

<--schnipp-->
procedure RemoveThread;
begin
  EnterCriticalSection(ThreadLock);
  try
    if ThreadCount = 1 then
       PostMessage(ThreadWindow, CM_DESTROYWINDOW, 0, 0);
  finally
    LeaveCriticalSection(ThreadLock);
  end;
end;
<--schnapp-->

sirius 20. Apr 2010 15:55

Re: WaitForMultipleObjects funktioniert irgendwie nicht
 
Dann such mal in der Unit nach "endthread" bzw. der funktion ThreadProc.

Edit: Aber wie gesagt, beim herauslaufen aus der ThreadFunc wird der Thread auch beendet.

Zitat:

How Threads are Terminated
A thread executes until one of the following events occurs:
  • The thread calls the ExitThread function.
  • Any thread of the process calls the ExitProcess function.
  • The thread function returns.
  • Any thread calls the TerminateThread function with a handle to the thread.
  • Any thread calls the TerminateProcess function with a handle to the process.
The exit code for a thread is either the value specified in the call to ExitThread, ExitProcess, TerminateThread, or TerminateProcess, or the value returned by the thread function.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:43 Uhr.

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