Дрейф часов на Windows - PullRequest
       37

Дрейф часов на Windows

15 голосов
/ 19 сентября 2008

Я разработал службу Windows, которая отслеживает деловые события. Он использует часы Windows для отметки времени событий. Тем не менее, лежащие в основе часы могут довольно сильно дрейфовать (например, терять несколько секунд в минуту), особенно когда процессоры усердно работают. Наши серверы используют службу времени Windows, чтобы поддерживать синхронизацию с контроллерами домена, которая использует NTP под капотом, но частота синхронизации контролируется политикой домена, и в любом случае даже синхронизация каждую минуту все равно допускает существенный сдвиг. Существуют ли какие-либо методы, которые мы можем использовать для поддержания стабильности часов, кроме использования аппаратных часов?

Ответы [ 13 ]

0 голосов
/ 19 сентября 2008

Я считаю, что служба времени Windows реализует только SNTP, который является упрощенной версией NTP. Полная реализация NTP учитывает стабильность ваших часов при принятии решения о частоте синхронизации.

Вы можете получить полный NTP-сервер для Windows здесь .

0 голосов
/ 19 сентября 2008

Однажды я написал класс Delphi для обработки повторной синхронизации по времени. Это наклеено ниже. Теперь, когда я вижу команду "w32tm", упомянутую Ларри Сильверманом, я подозреваю, что потратил впустую свое время.

unit TimeHandler;

interface

type
  TTimeHandler = class
  private
    FServerName : widestring;
  public
    constructor Create(servername : widestring);
    function RemoteSystemTime : TDateTime;
    procedure SetLocalSystemTime(settotime : TDateTime);
  end;

implementation

uses
  Windows, SysUtils, Messages;

function NetRemoteTOD(ServerName :PWideChar; var buffer :pointer) : integer; stdcall; external 'netapi32.dll';
function NetApiBufferFree(buffer : Pointer) : integer; stdcall; external 'netapi32.dll';

type
  //See MSDN documentation on the TIME_OF_DAY_INFO structure.
  PTime_Of_Day_Info = ^TTime_Of_Day_Info;
  TTime_Of_Day_Info = record
    ElapsedDate : integer;
    Milliseconds : integer;
    Hours : integer;
    Minutes : integer;
    Seconds : integer;
    HundredthsOfSeconds : integer;
    TimeZone : LongInt;
    TimeInterval : integer;
    Day : integer;
    Month : integer;
    Year : integer;
    DayOfWeek : integer;
  end;

constructor TTimeHandler.Create(servername: widestring);
begin
  inherited Create;
  FServerName := servername;
end;

function TTimeHandler.RemoteSystemTime: TDateTime;
var
  Buffer : pointer;
  Rek : PTime_Of_Day_Info;
  DateOnly, TimeOnly : TDateTime;
  timezone : integer;
begin
  //if the call is successful...
  if 0 = NetRemoteTOD(PWideChar(FServerName),Buffer) then begin
    //store the time of day info in our special buffer structure
    Rek := PTime_Of_Day_Info(Buffer);

    //windows time is in GMT, so we adjust for our current time zone
    if Rek.TimeZone <> -1 then
      timezone := Rek.TimeZone div 60
    else
      timezone := 0;

    //decode the date from integers into TDateTimes
    //assume zero milliseconds
    try
      DateOnly := EncodeDate(Rek.Year,Rek.Month,Rek.Day);
      TimeOnly := EncodeTime(Rek.Hours,Rek.Minutes,Rek.Seconds,0);
    except on e : exception do
      raise Exception.Create(
                             'Date retrieved from server, but it was invalid!' +
                             #13#10 +
                             e.Message
                            );
    end;

    //translate the time into a TDateTime
    //apply any time zone adjustment and return the result
    Result := DateOnly + TimeOnly - (timezone / 24);
  end  //if call was successful
  else begin
    raise Exception.Create('Time retrieval failed from "'+FServerName+'"');
  end;

  //free the data structure we created
  NetApiBufferFree(Buffer);
end;

procedure TTimeHandler.SetLocalSystemTime(settotime: TDateTime);
var
  SystemTime : TSystemTime;
begin
  DateTimeToSystemTime(settotime,SystemTime);
  SetLocalTime(SystemTime);
  //tell windows that the time changed
  PostMessage(HWND_BROADCAST,WM_TIMECHANGE,0,0);
end;

end.
0 голосов
/ 19 сентября 2008

На каких серверах вы работаете? В настольных компьютерах время, когда я сталкивался с этим, с включенной Spread Spectrum FSB, вызывает некоторые проблемы с синхронизацией прерываний, из-за чего эти часы тикают. Возможно, потребуется проверить, является ли эта опция в BIOS на одном из этих серверов, и отключить ее, если она включена.

Другой вариант - изменить интервал опроса времени и сделать его намного короче, используя следующий раздел реестра. Скорее всего, вам придется его добавить (обратите внимание, что это значение DWORD, а значение в секундах, например 600 на 10 минут):

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient\SpecialPollInterval

Вот полная обработка: KB816042

...