Entwickler-Ecke

Windows API - Dienst mit hoher CPU Auslastung


Jakane - Di 24.02.15 13:57
Titel: Dienst mit hoher CPU Auslastung
Hallo Delphi-Helfer

Ich habe einen Dienst mit Timer und dieser Timer soll bestimmte Dinge prüfen und erledigen.
Der Timer tut das mitlerweile Problemlos.

Mein Problem ist, dass selbst wenn der Timer ausgeschaltet ist,
ServiceExecute permanent arbeitet und damit auf Leistungsschwachen PCs zu bis zu 70% Auslastung führt.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TFÜDienst.ServiceExecute(Sender: TService);
begin
  _FÜ.TimerZeit.Enabled := True;

  while not Terminated do
  begin
    ServiceThread.ProcessRequests(False);
  end;

  _FÜ.TimerZeit.Enabled := False;
end;


Ich habe es mit Sleep(1) probiert, bei mir funktioniert es, aber dafür kann ich den Dienst nicht anhalten oder beenden (verständlicherweise)
aber auf dem schwachen PC startet der Dienst garnicht, weil er nicht rechtzeitig antwortet.

Kann man dem ServiceExecute beibringen nur auf den Timer zu warten, aber auch sich zu beenden, wenn ich den Dienst beenden will?


Narses - Di 24.02.15 16:27

Moin!

Probier das mal so (ungetestet):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure TFÜDienst.ServiceExecute(Sender: TService);
  const
    WAITFOR_MS = 1000// Wartezeit in Millisekunden
  var
    Tick: DWord;
    Event: THandle;
begin
  _FÜ.TimerZeit.Enabled := True;
  Event := CreateEvent(nil, False, False, nil);
  try
    while not Terminated and
          (MsgWaitForMultipleObjects(1, Event, False, WAITFOR_MS, QS_ALLINPUT) <> WAIT_TIMEOUT) do begin
      ServiceThread.ProcessRequests(False);
    end;
  finally
    CloseHandle(Event);
  end;
  _FÜ.TimerZeit.Enabled := False;
end;

cu
Narses


Jakane - Mi 25.02.15 11:36

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Moin!

Probier das mal so (ungetestet):

Delphi-Quelltext
1:
...                    

cu
Narses


Ich habe es getestet. Aber wie bei Sleep auch, bekomme ich die Meldung, das der Dienst nicht rechtzeitig antwortet.


Jakane - Do 26.02.15 19:37

Gibt es niemanden der das Problem kennt und lösen kann?
Order tritt das echt nur bei mir auf? :(


Narses - Do 26.02.15 20:12

Moin!

Ich probier gleich nochmal was aus :les: (das hatte ich auch schonmal, ich find nur das Projekt nicht wieder... :roll:).

cu
Narses


Narses - Do 26.02.15 23:32

Moin!

Hab mal eben ein Test-Projekt aufgesetzt:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, SvcMgr, Dialogs,
  ExtCtrls;

const
  LOGFILE_NAME = 'C:\test.log';

type
  TService1 = class(TService)
    Timer1: TTimer;
    procedure ServiceCreate(Sender: TObject);
    procedure ServiceStart(Sender: TService; var Started: Boolean);
    procedure ServiceExecute(Sender: TService);
    procedure ServiceStop(Sender: TService; var Stopped: Boolean);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    function GetServiceController: TServiceController; override;
    { Public-Deklarationen }
  end;

var
  Service1: TService1;

implementation

{$R *.DFM}

procedure ServiceController(CtrlCode: DWord); stdcall;
begin
  Service1.Controller(CtrlCode);
end;

function TService1.GetServiceController: TServiceController;
begin
  Result := ServiceController;
end;

procedure TService1.ServiceCreate(Sender: TObject);
  var
    LogFile: TFileStream;
begin
  if NOT FileExists(LOGFILE_NAME) then begin
    LogFile := TFileStream.Create(LOGFILE_NAME, fmCreate);
    LogFile.Free;
  end;
end;

procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
begin
  Timer1.Enabled := TRUE;
end;

procedure TService1.ServiceExecute(Sender: TService);
begin
  while NOT Terminated do
    ServiceThread.ProcessRequests(TRUE);
end;

procedure TService1.ServiceStop(Sender: TService; var Stopped: Boolean);
begin
  Timer1.Enabled := FALSE;
end;

procedure TService1.Timer1Timer(Sender: TObject);
  var
    LogFile: TFileStream;
    Msg: AnsiString;
begin
  LogFile := TFileStream.Create(LOGFILE_NAME, fmOpenReadWrite or fmShareDenyWrite);
  try
    Msg := DateTimeToStr(Now)+#13#10;
    LogFile.Seek(0, soFromEnd);
    LogFile.Write(PAnsiChar(Msg)^, Length(Msg));
  finally
    LogFile.Free;
  end;
end;

end.

Das tut was es soll und produziert bei mir auch keine hohe CPU-Last. :nixweiss:

cu
Narses


jaenicke - Fr 27.02.15 07:53

Der Unterschied ist, dass man mit True als Parameter für ProcessRequests wartet bis eine Nachricht zum Abarbeiten da ist, mit False aber nicht. Dadurch wird mit False die CPU Auslastung entsprechend hoch sein, wenn man nicht noch selbst eine kurze Wartezeit einbaut.