간단한 서비스를 실행합니다. SCM을 사용하여 시작할 수 있습니다. 나는 또한 조건이 사실이 될 때 스스로 멈추도록 서비스를 필요로한다.Delphi 서비스 자체가 중지되지 않습니다.
질문 1 : SCM을 사용할 때 서비스가 중지됩니다. 나는 "서비스 중지"를 클릭하고 거의 즉시 중단 할 서비스를 제공합니다. 그러나 나는 exe가 멈추기 전에 대략 10 초 동안 창 업무 명부에서 체재 한 ㄴ다는 것을주의했다. 그것은 정상적인 행동입니까?
질문 2 : 아래 코드 예제에서 변수를 증가시킴으로써 서비스가 중단되어야하는 조건을 시뮬레이트했습니다. 이 경우 서비스가 중지되지 않습니다. Windows 작업 관리자에서 작업을 중지해야합니다.
나는 여러 가지를 시도했지만 성공하지 못했습니다.
SCM을 사용하여 서비스를 중지하면 ServiceStop이 스레드 Kill 메서드를 호출하므로 스레드가 중지되고 서비스가 부드럽게 중지 될 수 있습니다.
서비스 자체를 중단하려는 경우 상태는 스레드 자체에서 테스트됩니다. 쓰레드는 멈추지 만 서비스는 멈춘다. 그래서 DoShutDown을 호출하여 서비스 중단을 알려야한다고 생각합니다. 하지만 멈추지 않습니다. DoShutDown 호출의 유무에 관계없이 서비스는 계속 유지됩니다.
내가 뭘 잘못하고 있니?
unit TestSvc;
interface
uses
System.SyncObjs
,SysUtils
,Windows
,SvcMgr
,Classes
;
Type
TSvcTh = class(TThread)
private
FEvent : TEvent;
FInterval : Cardinal;
vi_dbg : byte;
protected
procedure Execute; override;
procedure DoTimer;
public
procedure Kill;
Constructor Create();
Destructor Destroy; override;
end;
type
TMyService = class(TService)
procedure ServiceCreate(Sender: TObject);
procedure ServiceStart(Sender: TService; var Started: Boolean);
procedure ServiceShutdown(Sender: TService);
procedure ServiceStop(Sender: TService; var Stopped: Boolean);
private
SelfStop : Boolean;
Svc : TSvcTh;
public
function GetServiceController: TServiceController; override;
end;
var MyService: TMyService;
implementation
procedure ServiceController(CtrlCode: DWord); stdcall;
const sname='ServiceController';
begin
MyService.Controller(CtrlCode);
end;
function TMyService.GetServiceController: TServiceController;
const sname='TMyService.GetServiceController';
begin
Result := ServiceController;
end;
procedure TMyService.ServiceCreate(Sender: TObject);
const sname='TMyService.ServiceCreate';
begin
try
Name := SvcName;
except
on e: exception do begin
end;
end;
end;
procedure TMyService.ServiceShutdown(Sender: TService);
const sname='TMyService.ServiceShutdown';
var Stopped : boolean;
begin
ServiceStop(Self, Stopped);
end;
procedure TMyService.ServiceStart(Sender: TService; var Started: Boolean);
const sname='TMyService.ServiceStart';
begin
SelfStop := false;
Started := false;
try
Dbg(sname + ' ******* STARTING THREAD');
Svc := TSvcTh.Create;
Dbg(sname + '******* THREAD STARTED');
Started := true;
except
on e : exception do begin
Dbg(sname + '============== EXCEPTION =============>' + e.Message);
end;
end;
end;
procedure TMyService.ServiceStop(Sender: TService; var Stopped: Boolean);
const sname='TMyService.ServiceStop';
begin
try
Stopped := True;
if not SelfStop then begin
Dbg(sname + '*** Stop using service controller');
Svc.Kill;
Svc.WaitFor;
Svc.Free;
Svc := nil;
end
else begin
dbg(sname + ' *** Stop by the service itself ') ;
end;
except
on E : Exception do
begin
dbg(sname + ' Exception ! ' + e.Message);
end;
end;
Dbg(sname + '*** END');
end;
procedure TSvcTh.DoTimer;
const sname = 'TSvcTh.DoTimer';
begin
try
inc(vi_dbg);
Dbg(sname + '******* DoTimer');
except
on e : exception do begin
Dbg(sname +' ============== EXCEPTION =============>' + e.Message);
end;
end;
end;
procedure TSvcTh.Execute;
const sname = 'TSvcTh.Execute';
begin
while not Terminated do begin
try
case FEvent.WaitFor(FInterval) of
wrSignaled : begin // Triggered when we stop the service using service controller
Terminate;
end;
wrTimeout : begin
if not Servicemni.SelfStop then begin
DoTimer;
if vi_dbg > 5 then begin
MyService.SelfStop := true; // Testing auto stop
terminate;
end;
end;
end;
end;
except
on e : exception do begin
Dbg(sname + ' ============== EXCEPTION =============>' + e.Message);
end;
end;
end;
if MyService.SelfStop then begin
MyService.DoShutdown;
end;
Dbg(sname + ' ARRET ... ' + StrLog(MyService.Terminated));
if MyService.SelfStop then begin
MyService.ReportStatus;
end;
end;
Constructor TSvcTh.Create();
const sname = 'TSvcTh.Create';
begin
FEvent := TEvent.Create(nil, False, False, '');
FInterval := heartbeat;
vi_dbg := 0;
inherited Create(False);
end;
destructor TSvcTh.Destroy;
const sname = 'TSvcTh.Destroy';
begin
try
if assigned(FEvent) then begin
FreeAndNil(FEvent);
end;
except
on e:exception do begin
Dbg(sname + '==========================> EXCEPTION : '+ e.Message);
end;
end;
inherited;
end;
procedure TSvcTh.Kill;
const sname = 'TSvcTh.Kill';
begin
try
FEvent.SetEvent;
except
on e:exception do begin
dbg(sname + ' ==========================> EXCEPTION : '+ e.Message);
end;
end;
end;
end.
UPDATE :
나는 ServiceExecute 방법을 추가하고 (그것을 종료없이) true로 바로 설정 SelfStop에 SVC 스레드를 수정하는 경우, 서비스가 종료됩니다. 그러나 그것은 매우 우아하게 보이지 않습니다. 왜 필요한지 알 수 없습니다. 사실, 서비스는 "ServiceExecute"스레드를 만드는 것으로 보입니다. 그러나이 메소드를 작성하지 않으면 ProcessRequest가 호출되지 않고 Svc 스레드가 종료 될 때 "ServiceExecute"가 종료되지 않습니다. 또한 서비스 종료 후 Windows 작업 관리자 (sysinternals의 프로세스 탐색기)에서 프로세스가 약 30 초 동안 유지됩니다.
procedure TSvcTh.Execute;
const sname = 'TSvcTh.Execute';
begin
while not Terminated do begin
try
case FEvent.WaitFor(FInterval) of
wrSignaled : begin // Triggered when we stop the service using service controller
Terminate;
end;
wrTimeout : begin
DoTimer;
if vi_dbg > 5 then begin
MyService.SelfStop := true; // Testing auto stop
end;
end;
end;
except
on e : exception do begin
Dbg(sname + ' ============== EXCEPTION =============>' + e.Message);
end;
end;
end;
end;
procedure TMyService.ServiceExecute(Sender: TService);
begin
while not terminated do begin
ServiceThread.ProcessRequests(false);
if SelfStop then begin
ServiceThread.terminate;
Svc.Terminate;
Svc.WaitFor;
Svc.Free;
Svc := nil;
end;
sleep(1000);
end;
업데이트 2 : The explication for the delay of 30 seconds for the service to terminate seems to be here
. 내가 그랬다면 놀랍습니다. –
sname 상수에 대해 이야기하고 있습니까? 그냥 디버깅 목적으로. 로그에서 proc 이름을 얻는 유일한 방법. 코드는 여기 게시하기 위해 단순화되었습니다. 나는 상수를 제거하지 않았다. 그게 다야. 중지 된 변수는 설정되지 않고 읽혀지지 않습니다. SCM에서 사용하는 것 같습니다. – user2244705
나는 당신도 질문에서 그것들을 제거해야한다고 생각합니다.그런데 함수의 이름이 호출 스택 창에 표시되므로 생각하지 않아도됩니다. –