Czy istnieje alternatywna funkcja uśpienia w C do milisekund?


142

Mam kod źródłowy, który został skompilowany w systemie Windows. Konwertuję go, aby działał w systemie Red Hat Linux.

Kod źródłowy zawiera <windows.h>plik nagłówkowy, a programista użył tej Sleep()funkcji, aby czekać przez okres milisekund. To nie zadziała w systemie Linux.

Mogę jednak użyć tej sleep(seconds)funkcji, ale używa ona liczby całkowitej w sekundach. Nie chcę zamieniać milisekund na sekundy. Czy istnieje alternatywna funkcja uśpienia, której mogę używać podczas kompilowania gcc w systemie Linux?


sleep(/*seconds*/)w <unistd.h>działa, ale jeśli używam z printf("some things")bez \n, to nie działa.
EsmaeelE

Aby użyć w tym przypadku, musimy przepłukać wyjście fflush(stdout);po każdymprintf()
EsmaeelE

Odpowiedzi:


184

Tak - zdefiniowano starsze standardy POSIXusleep() , więc jest to dostępne w systemie Linux:

   int usleep(useconds_t usec);

OPIS

Funkcja usleep () zawiesza wykonywanie wątku wywołującego na (przynajmniej) usec mikrosekund. Sen może zostać nieco wydłużony przez dowolną aktywność systemu lub przez czas spędzony na przetwarzaniu połączenia lub przez ziarnistość zegarów systemowych.

usleep()zajmuje mikrosekundy , więc będziesz musiał pomnożyć dane wejściowe przez 1000, aby spać w milisekundach.


usleep()od tego czasu jest przestarzały, a następnie usunięty z POSIX; dla nowego kodu nanosleep()preferowane:

   #include <time.h>

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

OPIS

nanosleep()zawiesza wykonywanie wątku wywołującego do *reqczasu, gdy upłynie co najmniej czas określony w lub do dostarczenia sygnału, który wyzwala wywołanie procedury obsługi w wątku wywołującym lub kończy proces.

Przedział czasu struktury służy do określania przedziałów czasu z dokładnością do nanosekund. Jest zdefiniowany w następujący sposób:

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

Przykładowa msleep()funkcja zaimplementowana wykorzystująca nanosleep()kontynuację uśpienia w przypadku przerwania go sygnałem:

#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;
}

23
Dlaczego ciągle rezygnują z prostych funkcji dla skomplikowanych funkcji. Zamiast tracić mózg na nanosekundę (), równie dobrze można na razie wykorzystać funkcję usleep.

usleep nie może zrobić nano sekund, podczas gdy nanosleep powinien
muni764

55

Możesz użyć tej funkcji międzyplatformowej:

#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
    if (milliseconds >= 1000)
      sleep(milliseconds / 1000);
    usleep((milliseconds % 1000) * 1000);
#endif
}

3
Gdy nie mamy _POSIX_C_SOURCE >= 199309L, jak w przypadku -ansilub -std=c89, polecałbym użyć struct timeval tv; tv.tv_sec = milliseconds / 1000; tv.tv_usec = milliseconds % 1000 * 1000; select(0, NULL, NULL, NULL, &tv);zamiast usleep(milliseconds * 1000);. Kredyt jest tutaj .
Josh Sanford,

Świetna odpowiedź! Uwaga, oto nanosleep()dokumentacja: man7.org/linux/man-pages/man2/nanosleep.2.html . Przydatne byłoby zamieszczenie linków do dokumentacji dla każdej użytej tutaj funkcji specyficznej dla platformy.
Gabriel Staples

Należy również pamiętać, że podczas kompilacji ze gcc -Wall -g3 -std=c11 -o sleep_test sleep_test.c && ./sleep_testna Linux Ubuntu z gcc w wersji 4.8.4, pojawia się następujące ostrzeżenie: warning: implicit declaration of function ‘usleep’ [-Wimplicit-function-declaration]. Rozwiązaniem jest dodanie następujących 2 definicji na samej górze kodu: 1) #define __USE_POSIX199309i 2) #define _POSIX_C_SOURCE 199309L. Oba są wymagane, aby kod skompilował się bez żadnych ostrzeżeń (a także aby użyć nanoseconds()funkcji, która jest dostępna).
Gabriel Staples

Powiązana odpowiedź, którą właśnie stworzyłem: stackoverflow.com/a/55860234/4561887
Gabriel Staples

33

Alternatywnie do tego usleep(), co nie jest zdefiniowane w POSIX 2008 (chociaż zostało zdefiniowane do POSIX 2004 i jest ewidentnie dostępne na Linuksie i innych platformach z historią zgodności z POSIX), standard POSIX 2008 definiuje nanosleep():

nanosleep - sen o wysokiej rozdzielczości

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

nanosleep()Funkcja powoduje bieżący wątek zostać zawieszone wykonanie aż albo przedział czasu określony przez rqtpargumentu upłynął lub sygnał jest dostarczany do wątku wywołującego, a jego działanie jest wywołanie funkcji sygnału wzrok lub w celu zakończenia procesu. Czas zawieszenia może być dłuższy niż żądany, ponieważ wartość argumentu jest zaokrąglana w górę do całkowitej wielokrotności rozdzielczości uśpienia lub z powodu planowania innych działań przez system. Jednak z wyjątkiem przypadku przerwania przez sygnał, czas zawieszenia nie powinien być krótszy niż czas określony przez rqtp, mierzony przez zegar systemowy CLOCK_REALTIME.

Użycie nanosleep()funkcji nie ma wpływu na działanie lub blokowanie żadnego sygnału.


25

Poza uśpieniem , skromny wybór z zestawami deskryptorów plików NULL pozwoli Ci zatrzymać się z mikrosekundową precyzją i bez ryzyka SIGALRMkomplikacji.

sigtimedwait i sigwaitinfo oferują podobne zachowanie.


1
„bez ryzyka sigalarmu”: jakie ryzyko i który przypadek? wzywając spać i spać?
Massimo

2
@Massimo, połączona specyfikacja usleep zawiera kilka zdań na temat nieokreślonego zachowania SIGALARM. (Zasadniczo usleep i snu mogą być realizowane za pośrednictwem starego alarmu mechanizm, który można sobie wyobrazić by skomplikować bezpiecznego użytkowania usleep i SIGALARM. Nie wiem od każdego nowoczesnego systemu, który robi to w ten sposób, ale to wciąż w spec.)
pilcrow


-8
#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
To nie będzie spać przez milisekundy, a także wprowadza znacznie więcej narzutów, co sprawia, że ​​synchronizacja jest jeszcze bardziej zawodna.
Devolus

1
Przykład nie śpi przez mikrosekundy, a ponadto nie jest to dobre rozwiązanie w porównaniu z użyciem czegoś takiego jak usleep ().
Victor Ocampo,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.