Есть ли в C функция сна, альтернативная миллисекундам?

133

У меня есть исходный код, который был скомпилирован в Windows. Я конвертирую его для работы в Red Hat Linux.

Исходный код включает <windows.h>файл заголовка, и программист использовал Sleep()функцию для ожидания в течение миллисекунд. В Linux это не сработает.

Однако я могу использовать sleep(seconds)функцию, но она использует целое число в секундах. Я не хочу переводить миллисекунды в секунды. Есть ли альтернативная функция сна, которую я могу использовать при компиляции gcc в Linux?

ant2009
источник
sleep(/*seconds*/)в <unistd.h>работает, но если я использую printf("some things")без \n, он не работает.
EsmaeelE
Для использования в этом случае мы должны fflush(stdout);printf()
сбрасывать

Ответы:

179

Да - определены более старые стандарты POSIXusleep() , поэтому это доступно в Linux:

   int usleep(useconds_t usec);

ОПИСАНИЕ

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

usleep()занимает микросекунды , поэтому вам придется умножить ввод на 1000, чтобы засыпать в миллисекундах.


usleep()с тех пор устарел и впоследствии был удален из POSIX; для нового кода nanosleep()предпочтительно:

   #include <time.h>

   int nanosleep(const struct timespec *req, struct timespec *rem);

ОПИСАНИЕ

nanosleep()приостанавливает выполнение вызывающего потока до тех пор, пока не истечет, по крайней мере, время, указанное в *req, или пока не будет доставлен сигнал, запускающий вызов обработчика в вызывающем потоке или завершающий процесс.

Структура timespec используется для указания интервалов времени с точностью до наносекунды. Это определяется следующим образом:

       struct timespec {
           time_t tv_sec;        /* seconds */
           long   tv_nsec;       /* nanoseconds */
       };

Пример msleep()функции, реализованной с использованием nanosleep()продолжения сна, если он прерван сигналом:

#include <time.h>
#include <errno.h>    

/* msleep(): Sleep for the requested number of milliseconds. */
int msleep(long msec)
{
    struct timespec ts;
    int res;

    if (msec < 0)
    {
        errno = EINVAL;
        return -1;
    }

    ts.tv_sec = msec / 1000;
    ts.tv_nsec = (msec % 1000) * 1000000;

    do {
        res = nanosleep(&ts, &ts);
    } while (res && errno == EINTR);

    return res;
}
кафе
источник
19
Почему они продолжают отвергать простые функции для сложных функций. Вместо того, чтобы ломать себе голову на наносекунде (), можно на время использовать usleep.
52

Вы можете использовать эту кроссплатформенную функцию:

#ifdef WIN32
#include <windows.h>
#elif _POSIX_C_SOURCE >= 199309L
#include <time.h>   // for nanosleep
#else
#include <unistd.h> // for usleep
#endif

void sleep_ms(int milliseconds) // cross-platform sleep function
{
#ifdef WIN32
    Sleep(milliseconds);
#elif _POSIX_C_SOURCE >= 199309L
    struct timespec ts;
    ts.tv_sec = milliseconds / 1000;
    ts.tv_nsec = (milliseconds % 1000) * 1000000;
    nanosleep(&ts, NULL);
#else
    usleep(milliseconds * 1000);
#endif
}
Бернардо Рамос
источник
3
Когда у нас нет _POSIX_C_SOURCE >= 199309L, как в случае -ansiили -std=c89, я бы рекомендовал использовать struct timeval tv; tv.tv_sec = milliseconds / 1000; tv.tv_usec = milliseconds % 1000 * 1000; select(0, NULL, NULL, NULL, &tv);вместо usleep(milliseconds * 1000);. Кредит идет сюда .
Джош Сэнфорд
Отличный ответ! Обратите внимание, вот nanosleep()документация: man7.org/linux/man-pages/man2/nanosleep.2.html . Было бы полезно разместить ссылки на документацию для каждой используемой здесь функции для конкретной платформы.
Габриэль Стейплс
Также обратите внимание , что при компиляции с gcc -Wall -g3 -std=c11 -o sleep_test sleep_test.c && ./sleep_testна Linux Ubuntu с GCC версии 4.8.4, я получаю следующее предупреждение: warning: implicit declaration of function ‘usleep’ [-Wimplicit-function-declaration]. Решение состоит в том, чтобы добавить следующие 2 определения в самый верх вашего кода: 1) #define __USE_POSIX199309и 2) #define _POSIX_C_SOURCE 199309L. Оба необходимы для компиляции кода без каких-либо предупреждений (а также для использования nanoseconds()функции, которая у него есть).
Габриэль Стейплс
Связанный ответ, который я только что сделал: stackoverflow.com/a/55860234/4561887
Gabriel Staples
32

В качестве альтернативы тому usleep(), что не определено в POSIX 2008 (хотя оно было определено до POSIX 2004 и очевидно доступно на Linux и других платформах с историей соответствия POSIX), стандарт POSIX 2008 определяет nanosleep():

nanosleep - сон высокого разрешения

#include <time.h>
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);

nanosleep()Функция должна вызвать текущий поток быть отстранен от выполнения до либо временной интервал , указанный в rqtpаргументе не истечет или сигнал доставляется вызывающей нити, и его действие для вызова функции сигнала выделяющийся или прекратить процесс. Время приостановки может быть больше запрошенного, поскольку значение аргумента округлено до целого кратного разрешения сна или из-за планирования других действий системой. Но, за исключением случая прерывания сигналом, время приостановки не должно быть меньше времени, указанного в rqtp, как измерено системными часами CLOCK_REALTIME.

Использование nanosleep()функции не влияет на действие или блокировку любого сигнала.

Джонатан Леффлер
источник
24

Помимо usleep , скромный выбор с набором файловых дескрипторов NULL позволит вам делать паузу с точностью до микросекунд и без риска SIGALRMосложнений.

sigtimedwait и sigwaitinfo предлагают аналогичное поведение.

знак абзаца
источник
1
«без риска сигалармы»: какой риск и в каком случае? зовет спать и уснуть?
Massimo
2
@Massimo, связанная спецификация для usleep содержит несколько предложений о неуказанном поведении SIGALARM. (По сути, usleep и sleep могут быть реализованы через старый механизм сигнализации , который, как вы можете себе представить, усложнит безопасное использование usleep и SIGALARM. Я не знаю ни одной современной системы, которая делает это таким образом, но она все еще находится в spec.)
pilcrow
14
#include <unistd.h>

int usleep(useconds_t useconds); //pass in microseconds
Джонатан Леффлер
источник
-7
#include <stdio.h>
#include <stdlib.h>
int main () {

puts("Program Will Sleep For 2 Seconds");

system("sleep 2");      // works for linux systems


return 0;
}
Один
источник
1
Это не спит в течение миллисекунд, а также приводит к гораздо большим накладным расходам, что делает синхронизацию еще более ненадежной.
Devolus
1
Пример не спит микросекунды, плюс это не очень хорошее решение по сравнению с простым использованием чего-то вроде usleep ().
Виктор Окампо