Как сделать «long tv_nsec» и «time_t tv_sec» совместимыми?

#c #posix

#c #posix

Вопрос:

Я пишу функцию-оболочку sleep_new() clock_nanosleep() , для которой мне было бы проще приостановить поток.

 // POSIX.1-2017 is what compiler is confined to.
#define _XOPEN_SOURCE 700

#include <stdint.h>
#include <time.h>
#include <stdio.h>
#include <string.h>

// POSIX headers.

// Other headers
#include "sleep_new.h"

void sleep_new(long value, const char unit[3]){
    
    // Create a timespec structure and set it's members.
    // Members are added together!!! So to set time "1.5 s" we set "t.tv_sec = 1" and "t.tv_sec = 500000000".
    // Members ".tv_sec" and ".tv_nsec" represent unit and not value!
    struct timespec sleep_time;

    // Set flags i.e. TIMER_ABSTIME to 0 to use relative instead of absolute time.
    int flags = 0;

    // Choose the clock i.e. CLOCK_MONOTONIC is a "clock_id" for the clock started at system start.
    int clock_id = CLOCK_MONOTONIC;

    // Set timespec structure's members according to the chosen unit.
    if (!strcmp(unit, "s")) {
        sleep_time.tv_sec = value;
        sleep_time.tv_nsec = 0;
    }
    else if (!strcmp(unit, "ns")){
        sleep_time.tv_sec = 0;
        sleep_time.tv_nsec = value;
    }
    else if (!strcmp(unit, "us")){
        sleep_time.tv_sec = 0;
        sleep_time.tv_nsec = value * 1000;
    }
    else if (!strcmp(unit, "ms")){
        sleep_time.tv_sec = 0;
        sleep_time.tv_nsec = value * 1000000;
    }
    else{
        puts("Unit not supported - choose between: s, ms, us, nsn");
    }

    // Because last argument is NULL in case of error, remaining time is not stored in "t".
    clock_nanosleep(clock_id, flags, amp;sleep_time, NULL);

}

int main(int argc, char *argv[])
{
    // Counter.
    uint8_t i;

    for(i = 0; i < 256; i  ){
        // Stdout is newline  buffered. This is why we either have to include `n` at the end or flush() it manually.
        // So uncomment one example A or B.

        // A
        //printf("%dn", i);

        // B
        printf("%d, ", i);
        fflush(stdout);

        // Because last argument is NULL in case of error, remaining time is not stored in "t".
        sleep_new(1000, "ms");
    }

    return 0;

}
 

Если я вызываю эту функцию с sleep_new(1, "s") помощью or sleep_new(2, "s") , она работает нормально, потому что она устанавливает sleep_time.tv_nsec = 0; и sleep_time.tv_sec = value; .

В любых других сценариях, т.Е. sleep_new(1000, "ms") Что-то не так, и режим сна не применяется. Я отладил приложение, и значения применяются к timespec членам просто отлично, но clock_nanosec() просто игнорируют их.

введите описание изображения здесь

Я использую type long для value , потому что я прочитал здесь в POSIX, где заголовок time.h определяет timespec членов структуры tv_nsec , которые нуждаются long , и членов tv_sec , которые используют time_t , что, в свою очередь, определяется в заголовке sys/types.h следующим образом:

time_t должен быть целочисленным типом.

Поэтому, поскольку long он также может содержать int значения, я ожидал, что это сработает, но это не так. У кого-нибудь есть какие-либо предложения?

Ответ №1:

Это tv_nsec количество наносекунд в секунду — 1000 * 1000000 наносекунд слишком много. Это 1 секунда! tv_nsec должно варьироваться от 0 до 999999999 . Правильное вычисление может выглядеть так:

     sleep_time.tv_sec = value / 1000;
    sleep_time.tv_nsec = (value % 1000) * 1000000;
 

Комментарии:

1. Вот дерьмо. Я не знал, что tv_nsec это имеет верхний предел 999999999 … Я думал, что у long есть диапазон -9223372036854775808 до 922337203685477580 ?

2. Тип не имеет (почти) ничего общего с интерпретацией. и long имеет размер не менее 2 ^ 31 … 2 ^ 31 .

3. Можете ли вы объяснить, почему вы использовали целочисленное деление, а затем модулирование и умножение?

4. Я не верю, что смогу. Если у вас число больше 1000 , например 12345 , миллисекунд. Как бы вы извлекли из этого числа количество секунд и наносекунд? Возьмите лист бумаги и попытайтесь выяснить.