Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Sinnvolle Threadverwendung bei Server Monitor??? (https://www.delphipraxis.net/121579-sinnvolle-threadverwendung-bei-server-monitor.html)

Piro 30. Sep 2008 18:48


Sinnvolle Threadverwendung bei Server Monitor???
 
Hi Leute,

ich bin in unserer Firma ein Tool "Server Monitor" programmiert für ca. 70 Server. Die Aufgaben sind:
1. Online Check
2. Informationen mit Hilfe von WMI sammeln pro Server
3. Dienste von verschiedenen Server überwachen (mit Hilfe von WMI)

Das Programm läuft schon wunderbar. Ich habe nur das Problem, dass sich das Programm aufhängt nach ca. 2 Tagen. Nichts reagiert mehr.

Folgendes läuft im Hintergrund:
1. Alle 10 Sekunden werden die Server auf ihren Status geprüft ==> 70 Threads werden dazu erzeugt (Ping Funktion)...Dauer aller Threads = 5 Sekunden
2. Alle 20 Sekunden werden die Dienste überprüft ==> 20 Threads (WMI Abfrage)... Dauer aller Threads = 10 Sekunden
3. Alle 5 Minuten werden alle möglichen Daten (z.B.: Seriennummer, CPU, RAM, etc.) abgefragt ==> 70 Threads werden erzeugt (WMI Abfragen)...Dauer aller Threads = 1 Minute

Mir ist aufgefallen, dass die Ping Threads sich sauber beenden und keiner übrig bleibt. Bei den anderen kommt es vor, dass sie vereinzelt stehen bleiben und sich sogar vermehren.

Ich habe nur eine Thread Unit. Ich benutze TThread. Muss ich eventuell meine Logik ändern? Wie würdet ihr soetwas realsieren?

Aufruf der Threads durch den Timer am Beispiel der Diensteüberwachung:
Delphi-Quellcode:
procedure Tfrm_main.CheckServiceStatusThreadTerminate(Sender: TObject);
begin
 if ThreadCount_ServiceCheck = ThreadMax_ServiceCheck then
 begin
   ThreadsRunning_ServiceCheck := False;
   lbl_overview_servicecheck.Caption := FormatDateTime('dd. mmmm yyyy hh:nn:ss', now);
   if cb_setup_servicestatusactive.Checked = True then
     timer_checkservicestatus.Enabled := True;
 end;
 ThreadCount_ServiceCheck := ThreadCount_ServiceCheck + 1;
end;

procedure Tfrm_main.timer_checkservicestatusTimer(Sender: TObject);
var
 i     : Integer;
 Thread : MyThread;
begin
 while ThreadsRunning_ServerInfoToXML = True do
   Application.ProcessMessages;

 ThreadMax_ServiceCheck        := lv_service.Items.Count - 1;
 ThreadsRunning_ServiceCheck   := True;
 ThreadCount_ServiceCheck      := 0;

 for i := 0 to ThreadMax_ServiceCheck do
 begin
   timer_checkservicestatus.Enabled := False;
   ThreadsRunning_ServiceCheck     := True;
   Thread                          := MyThread.Create(True);
   Thread.art                      := 'CheckServiceStatus';
   Thread.user                     := edt_setup_user.Text;
   Thread.pwd                      := edt_setup_password.Text;
   Thread.lvid                     := i;
   Thread.service                  := lv_service.Items[i].SubItems[0];
   Thread.servicerestart           := lv_service.Items[i].SubItems[2];
   Thread.server                   := lv_service.Items[i].SubItems[3];
   Thread.lastStatus               := lv_service.Items[i].SubItemImages[4];
   Thread.OnTerminate              := CheckServiceStatusThreadTerminate;
   Thread.FreeOnTerminate          := True;
   Thread.Resume;
 end;
end;
Thread Unit:
Delphi-Quellcode:
unit uThread;

interface

uses
  Classes, SysUtils, MSXML2_TLB, ActiveX, Dialogs, uMain, uServer,
  ComCtrls, uHostAlive, WbemScripting_TLB, Variants;

type
  MyThread = class(TThread)
  private
    { Private-Deklarationen }
  protected
    procedure Execute; override;
    procedure CheckServerStatus;
    procedure ServerStatusToListView;
    procedure CheckServiceStatus;
    procedure ServiceStatusToListView;
    procedure ServerInformationToXML;
  public
    { Public-Deklarationen }
    art           : String;
    lvid          : Integer;
    lastStatus    : Integer;
    server        : String;
    sid           : String;
    curStatus     : String;
    user          : String;
    pwd           : String;
    service       : String;
    servicerestart : String;
  end;


implementation

uses uHostSocketAlive, DateUtils;

{ Wichtig: Methoden und Eigenschaften von Objekten in visuellen Komponenten dürfen
  nur in einer Methode namens Synchronize aufgerufen werden, z.B.

      Synchronize(UpdateCaption);

  und UpdateCaption könnte folgendermaßen aussehen:

    procedure MyThread.UpdateCaption;
    begin
      Form1.Caption := 'Aktualisiert in einem Thread';
    end; }

{ MyThread }

procedure MyThread.Execute;
begin
 CoInitialize(nil);
 try
   if art = 'CheckServerStatus' then
     CheckServerStatus;

   if art = 'CheckServiceStatus' then
     CheckServiceStatus;

   if (art = 'ServerInformationToXML') and (lastStatus = 1) then
       ServerInformationToXML;

 except
    on e: exception do begin
      // mache hier irgendetwas mit dem Fehler.
    end;
 end;
 CoUnInitialize();
end;

procedure MyThread.CheckServerStatus;
var
 i  : Integer;
 max : Integer;
begin
 // Verbindungsversuche
 max := 3;

 for i := 0 to max - 1 do
 begin
   if IsHostAlive(Server) = True then
   begin
     curStatus := '1'; //Server Online
     break;
   end
   else
     curStatus := '2'; //Server Offline
 end;

   Synchronize(ServerStatusToListView);
end;

procedure MyThread.ServerStatusToListView;
begin
 with frm_main.lv_server do
 begin
   case lastStatus of
     1 : begin
           if curStatus = '2' then
           begin
             Items[lvid].ImageIndex := 2;
             if frm_main.FirstStart = False then
               Items[lvid].SubItems[1] := 'off';
           end;
         end;
     2 : begin
           if curStatus = '1' then
           begin
             Items[lvid].ImageIndex := 1;
             if frm_main.FirstStart = False then
               Items[lvid].SubItems[1] := 'on';
           end;
         end;
   end;
 end;
end;

procedure MyThread.CheckServiceStatus;
var
 SWbemLocator1     : ISWbemLocator;
 aSrv             : ISWbemServices;
 vNVS             : OleVariant;
 aObjSet          : ISWbemObjectSet;
 aNVSDummy        : IDispatch;
 pEnum            : IEnumVARIANT;
 vOut             : OleVariant;
 dwRetrieved      : LongWord;
 hRes             : HResult;
begin
 try
   SWbemLocator1 := CoSWbemLocator.Create;
   // Für lokale Computer darf kein Benutzer und Passwort verwendet werden
   if UpperCase(server) <> UpperCase(GetEnvironmentVariable('COMPUTERNAME')) then
     aSrv := SWbemLocator1.ConnectServer(server,'root\cimv2',user, pwd,'','',0,vNVS)
   else
     aSrv := SWbemLocator1.ConnectServer(server,'root\cimv2','','','','',0,vNVS);

   aObjSet := aSrv.ExecQuery('Select * from Win32_Service Where Name = "' +service+'"','WQL', 0, aNVSDummy);
   pEnum := aObjSet.Get__NewEnum as IEnumVARIANT;
   hRes := pEnum.Next(1, vOut, dwRetrieved);
   if hRes = S_OK then
     curStatus := VarToStr(vOut.State);

   Free;
 Except
   curStatus := '';
 end;

 Synchronize(ServiceStatusToListView);
end;

procedure MyThread.ServiceStatusToListView;
begin
 with frm_main.lv_service do
 begin
   case lastStatus of
     16 : begin
            if curStatus <> 'Running' then
            begin
              Items[lvid].SubItemImages[4] := 17;
              if frm_main.FirstStart = False then
                //Items[lvid].SubItems[6] := 'down';
            end;
          end;
     17 : begin
            if curStatus = 'Running' then
            begin
              Items[lvid].SubItemImages[4] := 16;
              if frm_main.FirstStart = False then
                //Items[lvid].SubItems[6] := 'up';
            end;
          end;
     0,18 : begin
              if curStatus = 'Running' then
                Items[lvid].SubItemImages[4] := 16
              else
                Items[lvid].SubItemImages[4] := 17;
              end;
            end;
 end;
end;

// Gekürzter Quellcode
procedure MyThread.ServerInformationToXML;
var
...
begin
...
 try
   SWbemLocator1 := CoSWbemLocator.Create;
   // Für lokale Computer darf kein Benutzer und Passwort verwendet werden
   if UpperCase(server) <> UpperCase(GetEnvironmentVariable('COMPUTERNAME')) then
     aSrv := SWbemLocator1.ConnectServer(server,'root\cimv2',user, pwd,'','',0,vNVS)
   else
     aSrv := SWbemLocator1.ConnectServer(server,'root\cimv2','','','','',0,vNVS);

   //*** System Summary ***
   aObjSet := aSrv.ExecQuery('Select * from Win32_ComputerSystem','WQL', 0, aNVSDummy);
   ...

   //*** Operation System ***
   aObjSet := aSrv.ExecQuery('Select * from Win32_OperatingSystem','WQL', 0, aNVSDummy);
   ...

   //*** Prozessor Information ***
   aObjSet := aSrv.ExecQuery('Select * from Win32_Processor','WQL', 0, aNVSDummy);
   ...

   //*** Memory Information ***
   aObjSet := aSrv.ExecQuery('Select * from Win32_PhysicalMemory','WQL', 0, aNVSDummy);
   ...

   //*** Network Information ***
   aObjSet := aSrv.ExecQuery('Select * from Win32_NetworkAdapterConfiguration where IPEnabled = true','WQL', 0, aNVSDummy);
   ...

   //*** Storage Information ***
   aObjSet := aSrv.ExecQuery('Select * from Win32_LogicalDisk Where DriveType = 3','WQL', 0, aNVSDummy);
   ...

 Except
   //
 end;
end;

end.

Apollonius 30. Sep 2008 20:20

Re: Sinnvolle Threadverwendung bei Server Monitor???
 
So oft so viele Threads zu erzeugen ist nicht gut. Du hast hier einen klassischen Anwendungsfall für Thread Pools. Implementationen davon gibt es hier in der DP und seit Windows 2000 direkt im Betriebssystem.


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:15 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