Смещение часов в Windows

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

На самом деле это не вопрос, связанный с программированием, поэтому я не уверен, принадлежит ли он к StackOverflow.

Outlaw Programmer 19.09.2008 18:21

Похоже, это вопрос, связанный с программированием

Mark 03.05.2009 20:26

Дрейф часов на несколько секунд в минуту - это сломанные часы, независимо от того, насколько сильно машина работает. Вам нужно новое оборудование.

skaffman 04.09.2009 12:54

Вы не должны получать несколько секунд каждую минуту. Что-то не так с часами. Или у вас есть две программные службы, которые играют со временем на машине и меняют его из разных источников?

Matt 26.07.2011 14:36

Возможно, вы столкнулись с проблемой Microsoft Minute.

jww 30.04.2018 03:59
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
15
5
39 301
13

Ответы 13

Помимо более частой повторной синхронизации часов, я не думаю, что вы можете что-то сделать, кроме как приобрести новую материнскую плату, поскольку ваш тактовый сигнал, похоже, не находится на нужной частоте.

Увеличьте частоту повторной синхронизации. Если синхронизация выполняется с вашим собственным главным сервером в вашей сети, нет причин не синхронизировать каждую минуту.

Синхронизируйте чаще. Посмотрите на Записи реестра для службы W32Time, особенно на «Период». "SpecialSkew" звучит так, как будто это поможет вам.

Дрейф часов может быть следствием температуры; Может быть, вы могли бы попытаться получить более постоянную температуру - возможно, используя лучшее охлаждение? Однако вы никогда не потеряете дрейф полностью.

Использование внешних часов (приемник GPS и т. д.) И статистический метод для связи времени процессора с абсолютным временем - это то, что мы используем здесь для синхронизации событий в распределенных системах.

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

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

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

Вот полная работа над этим: KB816042

Вы можете запустить «w32tm / resync» в файле .bat запланированной задачи. Это работает в Windows Server 2003.

Однажды я написал класс 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.

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

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

Windows 2000 была последней версией, которая все еще использовала SNTP technet.microsoft.com/en-us/library/…

Bret Fisher 13.03.2012 19:01

Такты часов должны быть предсказуемыми, но на большинстве аппаратных средств ПК - потому что они не предназначены для систем реального времени - прерывания других устройств ввода-вывода имеют приоритет над прерываниями тактов, а некоторые драйверы выполняют обширную обработку в подпрограмме обслуживания прерываний. чем отложить его до отложенный вызов процедуры (DPC), что означает, что система может быть не в состоянии обслуживать прерывание по тактовому сигналу до (иногда) долгого времени после того, как о нем поступил сигнал.

К другим факторам относятся управляющие шиной контроллеры ввода-вывода, которые отбирают у ЦП много циклов шины памяти, в результате чего ему не хватает пропускной способности шины памяти в течение значительных периодов времени.

Как уже говорили другие, оборудование для генерации часов также может изменять свою частоту, поскольку значения компонентов меняются с температурой.

Windows позволяет регулировать количество тактов, добавляемых к часам реального времени при каждом прерывании: см. SetSystemTimeAdjustment. Однако это сработает только в том случае, если у вас будет предсказуемый сдвиг часов. Если часы немного отклоняются, клиент SNTP (служба «Время Windows») отрегулирует этот перекос, чтобы часы тикали немного быстрее или медленнее, чтобы приблизиться к правильному времени.

Не знаю, применимо ли это, но ...

В Windows есть проблема, заключающаяся в том, что если вы сильно измените разрешение таймера с помощью timeBeginPeriod (), часы будут дрейфовать.

На самом деле, в реализации Windows функции Java Thread wait()os::sleep()) есть ошибка, которая вызывает такое поведение. Он всегда устанавливает разрешение таймера на 1 мс перед ожиданием, чтобы быть точным (независимо от продолжительности сна), и восстанавливает его сразу после завершения, если другие потоки все еще не спят. Этот набор / сброс затем запутает часы Windows, которые ожидают, что квант времени Windows будет довольно постоянным.

Sun на самом деле имеет известно об этом с 2006 года и не исправляет его, AFAICT!

На самом деле из-за этого часы шли вдвое быстрее! Это поведение демонстрирует простая программа на Java, которая выполняет цикл на 1 миллисекунду.

Решение состоит в том, чтобы самостоятельно установить временное разрешение на что-нибудь низкое и поддерживать его как можно дольше. Используйте timeBeginPeriod (), чтобы контролировать это. (Мы установили его на 1 мс без каких-либо побочных эффектов.)

Для тех, кто кодирует на Java, более простой способ исправить это - создать поток, который бездействует, пока существует приложение.

Обратите внимание, что это устранит эту проблему на компьютере глобально, независимо от того, какое приложение является фактической причиной.

Ух ты. Я теряю несколько ЧАСОВ в день и много работаю с Java ...

deed02392 25.07.2013 16:52

@ deed02392: Кажется, время идет медленнее, когда вы работаете с Java. Это как застрять в 90-х. ;-п

Macke 12.08.2013 13:41

Вопрос: Применимо ли это только к java, или Delphi или C# могут вызывать аналогичные проблемы, когда много возятся с таймерами?

Vincent 11.10.2016 13:13

@Vincent: относится к любому приложению Windows, которое часто и часто вызывает timeBeginPeriod () с разными значениями.

Macke 11.10.2016 15:23

Поскольку похоже, что у вас большой бизнес:

Возьмите старый ноутбук или что-то, что не годится для многих, но, кажется, имеет более или менее надежные часы, и назовите его хронометристом. Единственная задача хронометриста - один раз каждые (скажем) 2 минуты посылать на серверы сообщение, указывающее время. Вместо того, чтобы использовать часы Windows для своих отметок времени, серверы будут записывать время с последнего сигнала хронометриста плюс время, прошедшее с момента сигнала. Проверяйте часы хронометриста по наручным часам один или два раза в неделю. Этого должно хватить.

Как уже упоминалось, эту проблему могут вызывать программы Java.

Другое решение, не требующее модификации кода, - это добавление аргумента виртуальной машины -XX:+ForceTimeHighResolution (находится в Страница поддержки NTP).

9.2.3. Windows and Sun's Java Virtual Machine

Sun's Java Virtual Machine needs to be started with the >-XX:+ForceTimeHighResolution parameter to avoid losing interrupts.

See http://www.macromedia.com/support/coldfusion/ts/documents/createuuid_clock_speed.htm for more information.

Из указанной ссылки (через Машина Wayback - исходная ссылка исчезла):

ColdFusion MX: CreateUUID Increases the Windows System Clock Speed

Calling the createUUID function multiple times under load in Macromedia ColdFusion MX and higher can cause the Windows system clock to accelerate. This is an issue with the Java Virtual Machine (JVM) in which Thread.sleep calls less than 10 milliseconds (ms) causes the Windows system clock to run faster. This behavior was originally filed as Sun Java Bug 4500388 (developer.java.sun.com/developer/bugParade/bugs/4500388.html) and has been confirmed for the 1.3.x and 1.4.x JVMs.

In ColdFusion MX, the createUUID function has an internal Thread.sleep call of 1 millisecond. When createUUID is heavily utilized, the Windows system clock will gain several seconds per minute. The rate of acceleration is proportional to the number of createUUID calls and the load on the ColdFusion MX server. Macromedia has observed this behavior in ColdFusion MX and higher on Windows XP, 2000, and 2003 systems.

http://www.codinghorror.com/blog/2007/01/keeping-time-on-the-pc.html

PC clocks should typically be accurate to within a few seconds per day. If you're experiencing massive clock drift-- on the order of minutes per day-- the first thing to check is your source of AC power. I've personally observed systems with a UPS plugged into another UPS (this is a no-no, by the way) that gained minutes per day. Removing the unnecessary UPS from the chain fixed the time problem. I am no hardware engineer, but I'm guessing that some timing signal in the power is used by the real-time clock chip on the motherboard.

Другие вопросы по теме