Как влияет системное время на спящие потоки? - PullRequest
6 голосов
/ 09 января 2009

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

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

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

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

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

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

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

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

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

Ответы [ 2 ]

3 голосов
/ 09 января 2009

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

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

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

2 голосов
/ 09 января 2009

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

...