Замена уснувшего на наноспальный

Я хочу заменить устаревшую функцию usleep на nanosleep в моем коде:

static int timediff( struct timeval *large, struct timeval *small )
{
        return (   ( ( large->tv_sec * 1000 * 1000 ) + large->tv_usec )
                 - ( ( small->tv_sec * 1000 * 1000 ) + small->tv_usec ) );
}

struct performance_s
{
        struct timeval acquired_input;
};

performance_t *performance_new( int fieldtimeus )
{
     performance_t *perf = malloc( sizeof( performance_t ) );
     if( !perf ) return 0;

     gettimeofday( &perf->acquired_input, 0 );

     return perf;
}

performance_t *perf = 0;

int performance_get_usecs_since_frame_acquired( performance_t *perf )
{
    struct timeval now;
    gettimeofday( &now, 0 );
    return timediff( &now, &perf->acquired_input );
}


int fieldtime = videoinput_get_time_per_field( norm );


if( rtctimer ) {
    while( performance_get_usecs_since_frame_acquired( perf )
                  < ( (fieldtime*2) - (rtctimer_get_usecs( rtctimer ) / 2) ) ) {
        rtctimer_next_tick( rtctimer );
    }
} else {
    int timeleft = performance_get_usecs_since_frame_acquired( perf );
    if( timeleft < fieldtime )
        usleep( fieldtime - timeleft );

Вопросы: дает ли эта замена такую ​​же точность по времени, как и при использовании usleep (и правильная ли это замена)?

struct timespec delay = {0, ( fieldtime - timeleft )}; nanosleep(&delay, NULL);

2 ответа

Одна из причин usleep устаревшим является то, что поведение, когда оно было прервано сигналом, было несовместимым среди исторических систем. В зависимости от ваших потребностей, это может означать вашу наивную замену nanosleep это не совсем то, что вы хотите. Особенно, nanosleep немедленно возвращается при выполнении любого обработчика сигнала, даже если обработчик сигнала был установлен с SA_RESTART, Так что вы можете сделать что-то вроде:

while (nanosleep(&delay, &delay));

чтобы сэкономить оставшееся время, если оно было прервано, и возобновить спящий режим на оставшееся время.

Обратите внимание, что nanosleep использования timespec, что в наносекундах, а не микросекундах. Таким образом, если значения вашего интервала в микросекундах, вы должны масштабировать их на 1000, чтобы получить наносекунды.

Также помните, что это ошибка (сообщается EINVAL) передать значение наносекунды меньше 0 или больше 1000000000 (1 секунда). timespec значения должны быть "нормализованы", то есть наносекунды должны находиться в диапазоне от 0 до 999999999 (включительно), а более крупные значения конвертируются для использования секунд (tv_sec) поле структуры.

Ваша основная цель здесь, чтобы спать до fieldtime микросекунды после получения предыдущего кадра. clock_nanosleep() Функция позволяет вам делать это напрямую - спать до тех пор, пока не будет достигнуто определенное абсолютное время, поэтому оно лучше подходит для ваших потребностей. Использование этой функции будет выглядеть так:

int fieldtime = videoinput_get_time_per_field( norm );
struct timespec deadline = performance->input;

deadline.tv_nsec += fieldtime * 1000L;
deadline.tv_sec += deadline.tv_nsec / 1000000000;
deadline.tv_nsec %= 1000000000;

while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &deadline, NULL) && errno == EINTR)
    ;

Это предполагает, что вы меняете performance->input быть struct timespec установить с помощью clock_gettime(CLOCK_MONOTONIC, &performance->input) скорее, чем gettimeofday(), CLOCK_MONOTONIC часы лучше подходят для этого случая, потому что на них не влияют изменения системного времени.

Другие вопросы по тегам