Как изменение системного времени влияет на спящие потоки?

StackOverflow https://stackoverflow.com/questions/427808

  •  06-07-2019
  •  | 
  •  

Вопрос

Если вы посмотрите на clock_gettime() функция, которая доступна во всех BSD и фактически определена как часть стандарта POSIX, вы видите, что существует поддержка как минимум трех типов часов (многие системы поддерживают больше, чем эти часы, но на самом деле стандарт POSIX требует только одного для присутствовать, все остальные не являются обязательными):

  • CLOCK_REALTIME - POSIX требует, чтобы это присутствовало.Это настенные часы.

  • CLOCK_MONOTONIC - Понятия не имею, что это такое (и что такое секунды СИ), но я понимаю, что эти часы никогда не прыгнут назад, они могут только монотонно увеличиваться в значении.

  • CLOCK_UPTIME - Я не вижу, чем это отличается от CLOCK_MONOTONIC (время безотказной работы также никогда не прыгает назад), но, по крайней мере, я знаю, что эти часы начинаются с нуля при загрузке ядра (тогда как не определено, какое начальное значение будет иметь CLOCK_MONOTONIC при загрузке ядра)

Давайте на секунду проигнорируем другие часы.CLOCK_REALTIME не гарантирует монотонный отсчет вверх, не так ли?Это фактическое «системное время».Я могу изменить системное время по своему желанию.Я могу установить его на 3 месяца в прошлое или на 5 лет в будущее, и каждый раз, когда моя система синхронизирует время с помощью NTP-сервера в сети, время может скакнуть вперед или назад.

Теперь у нас есть две спящие функции в системе BSD. спать() и наносон().Я не уверен, но я ожидаю, что сон() будет реализован поверх nanosleep, в конце концов я могу легко эмулировать сон() с помощью nanosleep() и устанавливать только количество секунд в спецификации времени структуры, сохраняя ноль наносекунд. .

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

Для меня все это совершенно разумно...но есть один вопрос, который меня всегда беспокоил:

Согласно различным источникам, сон (по крайней мере, наносон) использует CLOCK_REALTIME в качестве внутренних часов.Это означает, что если приказать nanosleep() заснуть на 30 секунд, а затем изменить системные часы на 1 час в будущем, поток проснется почти сразу (1 час в будущем намного опережает время пробуждения nanosleep( ) рассчитано).Это тоже совершенно нормально. Однако что произойдет, если я скажу «проснуться через 30 секунд», а затем пользователь узнает, что его системные часы идут на один час вперед, и переведет свои часы на один час назад?Тогда мой поток будет спать 1 час 30 секунд?Потому что это было бы довольно плохо.

Это было полезно?

Решение

Насколько я знаю, функции сна обычно реализуются скорее как уменьшающий счетчик.Вы говорите «спать 10 секунд», что в планировщике означает «спать в течение 1000 тактов расписания», а затем каждый раз, когда планировщик проверяет спящие процессы, он уменьшает оставшееся время.

Таким образом, время сна всегда будет количеством реального времени для сна, а не сна до некоторого времени в будущем.Причина этого, как вы и подозревали, заключается в том, что если мы выберем время в будущем, мы можем никогда туда не попасть (или можем попасть туда в неожиданное время).Это соответствует тому, для чего вы хотели бы использовать сон в программе.Он не предназначен для выполнения календарных вычислений.

Вы также можете провести простой тест, заставить программу спать на 30 секунд, использовать команду nix «time», чтобы определить, как долго работает функция, а после ее запуска перевести системные часы на 5 минут назад и посмотреть, что произойдет.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top