$ ./t_nanosleep 10 0 Сон на протяжении 10 секунд

Нажимаем Ctrl+C

Slept for: 1.853428 secs

Remaining: 8.146617000

Нажимаем Ctrl+C

Slept for: 4.370860 secs

Remaining: 5.629800000

Нажимаем Ctrl+C

Slept for: 6.193325 secs

Remaining: 3.807758000

Slept for: 10.008150 secs

Sleep complete

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

Как отмечалось ранее, в системах, поддерживающих высокоточные таймеры, точность сна может быть намного лучше, чем у программных часов.

Наличие округления означает, что, если сигналы принимают с высокой частотой, у нас могут возникнуть проблемы с подходом, который используется в программе из листинга 23.3. Дело в том, что при каждом повторном запуске nanosleep() будет накапливаться отклонение, связанное с округлением, так как вероятность того, что итоговое значение remain окажется кратным наименьшему интервалу программных часов, довольно низкая. Следовательно, каждый следующий вызов nanosleep() будет останавливать выполнение на более продолжительное время, чем указано в значении remain предыдущего вызова. В случае если сигналы доставляются с высокой частотой (то есть чаще, чем обновляются программные часы), процесс может никогда не выйти из состояния сна. В Linux 2.6 и выше эту проблему можно обойти с помощью вызова clock_nanosleep() и параметра TIMER_ABSTIME, которые будут рассмотрены в подразделе 23.5.4.

Листинг 23.3. Использование функции nanosleep()

timers/t_nanosleep.c

#define _POSIX_C_SOURCE 199309

#include

#include

#include

#include "tlpi_hdr.h"

static void

sigintHandler(int sig)

{

return; /* Просто прерываем nanosleep() */

}

int

main(int argc, char *argv[])

{

struct timeval start, finish;

struct timespec request, remain;

struct sigaction sa;

int s;

if (argc!= 3 || strcmp(argv[1], "-help") == 0)

usageErr("%s secs nanosecs\n", argv[0]);

request.tv_sec = getLong(argv[1], 0, "secs");

request.tv_nsec = getLong(argv[2], 0, "nanosecs");

/* Позволяем обработчику SIGINT прерывать nanosleep() */

sigemptyset(&sa.sa_mask);

sa.sa_flags = 0;

sa.sa_handler = sigintHandler;

if (sigaction(SIGINT, &sa, NULL) == –1)

errExit("sigaction");

if (gettimeofday(&start, NULL) == –1)

errExit("gettimeofday");

for (;;) {

s = nanosleep(&request, &remain);

if (s == –1 && errno!= EINTR)

errExit("nanosleep");

if (gettimeofday(&finish, NULL) == –1)

errExit("gettimeofday");

printf("Slept for: %9.6f secs\n", finish.tv_sec — start.tv_sec +

(finish.tv_usec — start.tv_usec) / 1000000.0);

if (s == 0)

break; /* Вызов nanosleep() завершен */

printf("Remaining: %2ld.%09ld\n", (long) remain.tv_sec, remain.tv_nsec);

request = remain; /* Следующий переход в режим сна будет

длиться оставшееся время */

}

printf("Sleep complete\n");

exit(EXIT_SUCCESS);

}

timers/t_nanosleep.c

23.5. Часы стандарта POSIX

POSIX-часы (изначально разработанные для стандарта POSIX.1b) предоставляют программный интерфейс для доступа к часам, которые измеряют время в наносекундах. Для представления такого времени используется та же структура timespec, которую мы применяли в подразделе 23.4.2 в вызове nanosleep().

В Linux программы, которые работают с этим интерфейсом, должны быть скомпилированы с параметром — lrt, иначе их нельзя будет скомпоновать с библиотекой реального времени librt.

Главными системными вызовами программного интерфейса POSIX-часов являются clock_gettime(), который возвращает текущее значение часов, clock_getres(), позволяющий определить их точность, и clock_settime(), который обновляет часы.

23.5.1. Получение текущего значения часов: вызов clock_gettime()

Системный вызов clock_gettime() возвращает время в соответствии с часами, указанными в аргументе clockid.

#define _POSIX_C_SOURCE 199309

#include

int clock_gettime(clockid_t clockid, struct timespec *tp);

int clock_getres(clockid_t clockid, struct timespec *res);

Оба вызова возвращают 0 при успешном завершении или –1, если случилась ошибка

На значение времени, возвращаемое внутри структуры timespec, указывает аргумент tp. И хотя структура timespec поддерживает наносекунды, значение, возвращенное вызовом clock_gettime(), может оказаться менее точным. Системный вызов clock_getres() возвращает указатель на структуру timespec (аргумент clockid), в которой содержится точность часов.

Тип данных clockid_t предусмотрен стандартом SUSv3 для представления идентификатора часов. Значения, которые можно указывать в аргументе clockid, перечислены в первом столбце табл. 23.1.

Таблица 23.1. Типы часов стандарта POSIX.1b

Идентификатор часов — Описание

Перейти на страницу:

Похожие книги