Einzelnen Beitrag anzeigen

El.Blindo

Registriert seit: 24. Okt 2006
18 Beiträge
 
#1

Thread sauber Beenden ? Handle ungültig.

  Alt 29. Jan 2008, 19:07
Nächster Tag, nächste dumme Frage.

Ich bastel zur Zeit an einem Programm das mit diverse Threads arbeitet, in diesem Beispiel-Thread wird unter anderem ein DLL Funktion importiert, ferner hole ich mir ein Handel im Zusammenhang mit der PDH.DLL.

Dieser Thread läuft in einer Endlos-Schleife (While not Terminated.....).

Nun würde ich gerne beim Beenden des Hauptprogrammes, auch diesen Thread sauber beenden, d.h. meine DLL sowie mein Handle wieder freigeben.

Hier die Thread Unit:

Delphi-Quellcode:
unit PDHThread;

interface

uses
  Classes, Windows, SysUtils;

const
  PDH_NO_DATA = $800007D5;
  PDH_MEMORY_ALLOCATION_FAILURE = $C0000BBB;
  PDH_INVALID_HANDLE = $C0000BBC;
  PDH_INVALID_ARGUMENT = $C0000BBD;

  PDH_FMT_RAW = $00000010;
  PDH_FMT_ANSI = $00000020;
  PDH_FMT_UNICODE = $00000040;
  PDH_FMT_LONG = $00000100;
  PDH_FMT_DOUBLE = $00000200;
  PDH_FMT_LARGE = $00000400;
  PDH_FMT_NOSCALE = $00001000;
  PDH_FMT_1000 = $00002000;
  PDH_FMT_NODATA = $00004000;
  PDH_FMT_NOCAP100 = $00008000;

type
  PQUERY = ^HQUERY;
  HQUERY = THandle;

  PCOUNTER = ^HCOUNTER;
  HCOUNTER = THandle;

  PDH_STATUS = Longint;

  PPDH_FMT_COUNTERVALUE = ^TPDH_FMT_COUNTERVALUE;
  _PDH_FMT_COUNTERVALUE = record
    CStatus : DWORD;
    longValue : Longint;
    doubleValue : double;
    largeValue : LONGLONG;
    AnsiStringValue : LPCSTR;
    WideStringValue : LPCWSTR;
  end;
  TPDH_FMT_COUNTERVALUE = _PDH_FMT_COUNTERVALUE;
  PDH_FMT_COUNTERVALUE = _PDH_FMT_COUNTERVALUE;

type
  TPDHInfo = record
    Counter : HCounter;
    PDHLoad : PDH_FMT_COUNTERVALUE;
  end;

type
  TPDHThread = class(TThread)
  private
    HQ : HQuery;
    PDHInfo : Array[1..4] of TPDHInfo;
    hPDH : THandle;
    procedure UpdatePDH;
  protected
    procedure Execute; override;
  public
  end;

Var
  PdhOpenQuery : function(pReserved: Pointer; dwUserData: DWORD; phQuery: PQUERY): PDH_STATUS; stdcall;
  PdhCloseQuery : function(ahQuery: HQUERY): PDH_STATUS; stdcall;
  PdhAddCounter : function(ahQuery: HQUERY; szFullCounterPath: PChar; dwUserData: DWORD; phCounter: PCOUNTER ): PDH_STATUS; stdcall;
  PdhRemoveCounter : function( ahCounter: HCOUNTER ): PDH_STATUS; stdcall;
  PdhCollectQueryData : function( ahQuery: HQUERY ): PDH_STATUS; stdcall;
  PdhValidatePath : function( szFullCounterPath: PChar ): PDH_STATUS; stdcall;
  PdhGetFormattedCounterValue : function( ahCounter: HCOUNTER; dwFormat: DWORD; lpdwType: LPDWORD; pValue: PPDH_FMT_COUNTERVALUE): PDH_STATUS; stdcall;

implementation

uses Main;

function GetNumberOfProcessors: Integer;
var
  SystemInfo: TSystemInfo;
begin
  GetSystemInfo(SystemInfo);
  Result:=SystemInfo.dwNumberOfProcessors;
end;

Function LoadPDH : THandle;
Var
  H : THandle;
Begin
  H := LoadLibrary('PDH.DLL');
  If H <> 0 then
  Begin
    PdhOpenQuery := GetProcAddress(H, 'PdhOpenQuery');
    PdhCloseQuery := GetProcAddress(H, 'PdhCloseQuery');
    PdhAddCounter := GetProcAddress(H, 'PdhAddCounterA');
    PdhRemoveCounter := GetProcAddress(H, 'PdhRemoveCounter');
    PdhCollectQueryData := GetProcAddress(H, 'PdhCollectQueryData');
    PdhValidatePath := GetProcAddress(H, 'PdhValidatePath');
    PdhGetFormattedCounterValue := GetProcAddress(H, 'PdhGetFormattedCounterValue');
  End;
  Result := H;
End;

procedure TPDHThread.Execute;
var
  X, MaxX : Integer;
  dwctrType : DWord;
begin
  hPDH := LoadPDH;
  If hPDH <> 0 then
  Begin
    If PDHOpenQuery(nil, 1 ,@HQ) = ERROR_SUCCESS then
    Begin
      MaxX := GetNumberOfProcessors;
      If MaxX > 4 then
        MaxX := 4;
      For X := 1 to MaxX do
        If PDHAddCounter(HQ, PChar('\Prozessor('+InttoStr(X-1)+')\Prozessorzeit (%)'), 1, @PDHInfo[X].Counter) <> ERROR_SUCCESS then
          PDHAddCounter(HQ, PChar('\Processor('+InttoStr(X-1)+')\% Processor Time'), 1, @PDHInfo[X].Counter);
      while not Terminated do
      Begin
        If PDHCollectQueryData(HQ) = ERROR_SUCCESS then
          For X := 1 to MaxX do
            PdhGetFormattedCounterValue(PDHInfo[X].Counter, PDH_FMT_DOUBLE, @dwctrType, @PDHInfo[X].PDHLoad);
        Synchronize(UpdatePDH);
        Sleep(1000);
      End;
    PdhCloseQuery(HQ);
    FreeLibrary(hPDH);
    End;
  End;
end;

procedure TPDHThread.UpdatePDH;
begin
  MainForm.UpdatePDH(PDHInfo);
end;

end.
Dieser Thread wird im Hauptprogramm folgendermaßen gestartet:

Delphi-Quellcode:
  // Thread zur Berechnung des CPULoad starten
  PDHThread := TPDHThread.Create(True);
  PDHThread.Priority := tpNormal;
  PDHThread.FreeOnTerminate := True;
  PDHThread.Resume;
Beim Testen des Ganzen bin ich jedoch darauf gestoßen das weder PdhCloseQuery noch FreeLibrary ausgeführt werden.

Also hab ich das Ganze geändert, so:

Delphi-Quellcode:
  // Thread zur Berechnung des CPULoad starten
  PDHThread := TPDHThread.Create(True);
  PDHThread.Priority := tpNormal;
  PDHThread.FreeOnTerminate := False;
  PDHThread.Resume;
Und habe im OnDestroy Event (wahlweise auch im OnCloseQuery) des Hauptprogrammes folgendes eingeführt:

Delphi-Quellcode:
  // Thread zur Berechnung des CPULoad beenden
  PDHThread.Terminate;
  PDHThread.Waitfor;
  PDHThread.Free;
Nun werden PdhCloseQuery und FreeLibrary ausgeführt, allerdings fange ich mir Exceptions.

Handle ist ungültig(6) oder Read of Address 0001.

Wo liegt mein Fehler ?

Wenn ich FreeOnterminate auf True setze ist es für mich noch verständlich, offensichtlich wird der Thread abgewürgt bevor PdhCloseQuery und FreeLibrary ausgeführt werden.

Bei FreeOnterminate auf False, wenn ich den Thread also selber beende, müssten doch die Handles auf hPDH und HQ weiter gültig sein, zumindestens so lange bis ich sie selber frei gebe, oder PDHThread.Free aufrufe. ODER ?

MfG

El.Blindo
  Mit Zitat antworten Zitat