8.10. Функция nanosleep(): высокоточная пауза
8.10. Функция nanosleep(): высокоточная пауза
Функция nanosleep() является более точной версией стандартной функции sleep(), принимая указатель на структуру типа timespec, где время задается с точностью до наносекунды, а не секунды. Правда, особенности работы ОС Linux таковы, что реальная точность оказывается равной 10 мс, но это все равно выше, чем в функции sleep(). Функцию nanosleep() можно использовать в приложениях, где требуется запускать различные операции с короткими интервалами между ними.
В структуре timespec имеются два поля:
? tv_sес — целое число секунд;
? tv_nsec — дополнительное число миллисекунд (должно быть меньше, чем 109).
Работа функции nanosleep(), как и функции sleep(), прерывается при получении сигнала. При этом функция возвращает значение -1, а в переменную errno записывается код EINTR. Но у функции nanosleep() есть важное преимущество. Она принимает дополнительный аргумент — еще один указатель на структуру timespec, в которую (если указатель не равен NULL) заносится величина оставшегося интервала времени (т.е. разница между запрашиваемым и прошедшим промежутками времени). Благодаря этому можно легко возобновлять прерванные операции ожидания.
В листинге 8.8 показана альтернативная реализация функции sleep(). В отличие от стандартного системного вызова эта функция может принимать дробное число секунд и возобновлять операцию ожидания в случае прерывания по сигналу.
Листинг 8.8. (better_sleep.c) Высокоточная реализация функции sleep()
#include <errno.h>
#include <time.h>
int better_sleep(double sleep_time) {
struct timespec tv;
/* Заполнение структуры timespec на основании указанного числа
секунд. */
tv.tv_sec = (time_t)sleep_time;
/* добавление неучтенных выше наносекунд. */
tv.tv_nsec = (long)((sleep_time - tv.tv_sec) * 1e+9);
while (1) {
/* Пауза, длительность которой указана в переменной tv.
В случае прерывания по сигналу величина оставшегося
промежутка времени заносится обратно в переменную tv. */
int rval = nanosleep(&tv, &tv);
if (rval == 0)
/* пауза успешно окончена. */
return 0;
else if (errno == EINTR)
/* Прерывание по сигналу. Повторная попытка. */
continue;
else
/* Какая-то другая ошибка. */
return rval;
}
return 0;
}