某程序因调用外部库比较多,容易异常退出,一时间未找到具体问题点,先让程序实现崩溃时自启动临时对付对付。
基本原理是以自身程序作为deamon进程,再通过参数(-child)控制启动子进程,加载自身业务真正需要运行的代码,deamon进程通过WaitForSingleObject等候子进程状态返回,当子进程非正常退出(exitcode <>0)则重启子进程。
unit uDeamon; { 为减少其它单元initialization段加载造成的开销, 此单元需前置加载 } interface uses Windows, SysUtils; function isDeamonProcess():Boolean; implementation uses uLog; procedure runDeamon(); var si: TStartupInfo; pi: TProcessInformation; exitCode: Cardinal; exePath, command: String; i, exitCount: Integer; begin ZeroMemory(@si, SizeOf(si)); ZeroMemory(@Pi, SizeOf(pi)); si.cb := SizeOf(si); exePath := ParamStr(0); for i := 1 to ParamCount do command := command + ' ' + ParamStr(i); command := exePath + ' ' + command + ' -child'; Log('Start child process: ' + command); exitCount := 0; repeat if CreateProcess(nil, PChar(command), nil, nil, False, 0, nil, PChar(ExtractFileDir(exePath)), si, pi) then begin CloseHandle(pi.hThread); WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, exitCode); Inc(exitCount); Log('Child exit: ' + IntToStr(exitCode) + ', Exit times: ' + IntToStr(exitCount)); CloseHandle(pi.hProcess); if exitCount >= 20 then begin // 连续重启超过20次后, 不再进行重启. Log('Too many times to restart, an unrecoverable error maybe occur, child process will not be restart.'); Break; end; end else Break; until exitCode = 0; end; function hasChildParam(): Boolean; var i: Integer; begin Result := False; for I := 1 to ParamCount do begin if SameText(ParamStr(i), '-child') then begin Result := True; Break; end; end; end; function isDeamonProcess(): Boolean; begin Result := not hasChildParam(); end; initialization // 减少deamon进程开销, 在initialization段即执行相关代码 if not hasChildParam then begin runDeamon; ExitProcess(0); end; end.