Как проверить, поддерживает ли система «Монотонные часы»? - PullRequest
0 голосов
/ 09 мая 2018

Мне нужно обработать сценарии тайм-аута в коде и хочу использовать clock_gettime(CLOCK_MONOTONIC), если система поддерживает монотонные часы.

#ifdef CLOCK_MONOTONIC
    clock_gettime(CLOCK_MONOTONIC, & spec);
#else
    clock_gettime(CLOCK_REALTIME,  & spec);
#endif

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

Ответы [ 3 ]

0 голосов
/ 09 мая 2018

В соответствии с буквой POSIX, вам может потребоваться проверка во время выполнения, даже если определена константа CLOCK_MONOTONIC.Официальный способ справиться с этим - с помощью _POSIX_MONOTONIC_CLOCK «макроса функционального теста», но у этих макросов действительно сложная семантика: цитирование http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html,

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

Перевод этого трехстороннего различия в код даст вам что-то вроде этого:

#if !defined _POSIX_MONOTONIC_CLOCK || _POSIX_MONOTONIC_CLOCK < 0
    clock_gettime(CLOCK_REALTIME, &spec);
#elif _POSIX_MONOTONIC_CLOCK > 0
    clock_gettime(CLOCK_MONOTONIC, &spec);
#else
    if (clock_gettime(CLOCK_MONOTONIC, &spec))
        clock_gettime(CLOCK_REALTIME, &spec));
#endif

Но это проще и более читабельно, если вы просто всегда выполняете тест выполнения, когда определен сам CLOCK_MONOTONIC:

#ifdef CLOCK_MONOTONIC
    if (clock_gettime(CLOCK_MONOTONIC, &spec))
#endif
        clock_gettime(CLOCK_REALTIME, &spec);

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

Существует также довольно веский аргумент в пользу безоговорочного использования CLOCK_MONOTONIC;вы с большей вероятностью найдете операционную систему, которая вообще не поддерживает clock_gettime (например, MacOS X, насколько я знаю, ее пока не имеет), чем операционная система, которая имеет clock_gettime, но не CLOCK_MONOTONIC.

0 голосов
/ 09 мая 2018

Как показано в ответе @ zwol, все становится немного сложнее и интереснее -

См. Следующую простую программу (foo.c):

#include <stdio.h>
#include <unistd.h>
#include <time.h>

int
main()
{
    struct timespec spec;

    printf("_POSIX_MONOTONIC_CLOCK         = %d\n",
           (int)_POSIX_MONOTONIC_CLOCK);
    printf("sysconf(_SC_MONOTONIC_CLOCK)   = %ld\n",
           sysconf(_SC_MONOTONIC_CLOCK) );
    printf("clock_gettime(CLOCK_MONOTONIC) = %d\n",
           clock_gettime(CLOCK_MONOTONIC, & spec) );

    return 0;
}

В Linux (Debian 9, x86_64):

[STEP 101] # uname -a
Linux debian9 4.9.0-6-amd64 #1 SMP Debian 4.9.88-1 (2018-04-29) x86_64 GNU/Linux
[STEP 102] # gcc foo.c && ./a.out
_POSIX_MONOTONIC_CLOCK         = 0
sysconf(_SC_MONOTONIC_CLOCK)   = 200809
clock_gettime(CLOCK_MONOTONIC) = 0
[STEP 103] #

В macOS (10.13, High Sierra):

[STEP 201] $ uname -a
Darwin macbook.home 17.5.0 Darwin Kernel Version 17.5.0: Fri Apr 13 19:32:32 PDT 2018; root:xnu-4570.51.2~1/RELEASE_X86_64 x86_64
[STEP 202] $ cc foo.c && ./a.out
_POSIX_MONOTONIC_CLOCK         = -1
sysconf(_SC_MONOTONIC_CLOCK)   = -1
clock_gettime(CLOCK_MONOTONIC) = 0
[STEP 203] $

В FreeBSD (11.1, x86_64):

[STEP 301] # uname -a
FreeBSD freebsd 11.1-RELEASE FreeBSD 11.1-RELEASE #0 r321309: Fri Jul 21 02:08:28 UTC 2017     root@releng2.nyi.freebsd.org:/usr/obj/usr/src/sys/GENERIC  amd64
[STEP 302] # cc foo.c && ./a.out 
_POSIX_MONOTONIC_CLOCK         = 200112
sysconf(_SC_MONOTONIC_CLOCK)   = 200112
clock_gettime(CLOCK_MONOTONIC) = 0
[STEP 303] #

Результат на macOS действительно удивил меня. sysconf() возвращает -1, но clock_gettime(CLOCK_MONOTONIC) успешно! Не уверен, что это означает, что macOS не соответствует POSIX. В любом случае это доказывает, что проверка во время выполнения с sysconf() не надежна!

Наконец-то я пойду с этим:

int
Clock_gettime(struct timespec * spec)
{
    static bool firstime = true;
    static clockid_t clock = CLOCK_REALTIME;

    if (firstime) {
        firstime = false;
#ifdef CLOCK_MONOTONIC
        if (clock_gettime(CLOCK_MONOTONIC, spec) == 0) {
            clock = CLOCK_MONOTONIC;
            return 0;
        }
#endif
    }

    return clock_gettime(clock, spec);
}
0 голосов
/ 09 мая 2018

POSIX требует только присутствия CLOCK_REALTIME, другие часы не обязательны.

Если доступны монотонные часы, макрос _POSIX_MONOTONIC_CLOCK будет определен в unistd.h (в соответствии с разделом Доступность справочной страницы )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...