Gibt es eine alternative Schlaffunktion in C zu Millisekunden?

133

Ich habe einen Quellcode, der unter Windows kompiliert wurde. Ich konvertiere es, um unter Red Hat Linux zu laufen.

Der Quellcode enthält die <windows.h>Header-Datei und der Programmierer hat die Sleep()Funktion verwendet, um eine Zeitspanne von Millisekunden zu warten. Dies funktioniert unter Linux nicht.

Ich kann die sleep(seconds)Funktion jedoch verwenden, aber das verwendet eine Ganzzahl in Sekunden. Ich möchte keine Millisekunden in Sekunden konvertieren. Gibt es eine alternative Schlaffunktion, die ich beim Kompilieren von gcc unter Linux verwenden kann?

ant2009
quelle
sleep(/*seconds*/)in <unistd.h>funktioniert, aber wenn ich mit printf("some things")ohne benutze \n, funktioniert es nicht.
EsmaeelE
Für die Verwendung in diesem Fall müssen wir die Ausgabe fflush(stdout);nach jedemprintf()
EsmaeelE

Antworten:

179

Ja - ältere POSIX- Standards sind definiert usleep(), daher ist dies unter Linux verfügbar:

   int usleep(useconds_t usec);

BESCHREIBUNG

Die Funktion usleep () unterbricht die Ausführung des aufrufenden Threads für (mindestens) usec Mikrosekunden. Der Ruhezustand kann durch eine Systemaktivität oder durch die für die Verarbeitung des Anrufs aufgewendete Zeit oder durch die Granularität der Systemzeitgeber geringfügig verlängert werden.

usleep()dauert Mikrosekunden , daher müssen Sie die Eingabe mit 1000 multiplizieren, um in Millisekunden zu schlafen.


usleep()wurde inzwischen veraltet und anschließend aus POSIX entfernt; für neuen Code nanosleep()wird bevorzugt:

   #include <time.h>

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

BESCHREIBUNG

nanosleep()Unterbricht die Ausführung des aufrufenden Threads, bis entweder mindestens die in angegebene Zeit *reqverstrichen ist oder ein Signal übermittelt wird, das den Aufruf eines Handlers im aufrufenden Thread auslöst oder den Prozess beendet.

Die Strukturzeitangabe wird verwendet, um Zeitintervalle mit Nanosekundengenauigkeit anzugeben. Es ist wie folgt definiert:

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

Eine Beispielfunktion msleep(), die implementiert wurde, indem nanosleep()der Schlaf fortgesetzt wird, wenn er durch ein Signal unterbrochen wird:

#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;
}
caf
quelle
18
Warum lehnen sie einfache Funktionen für komplizierte Funktionen immer wieder ab? Anstatt Ihr Gehirn in Nanosekunden () zu zerstören, sollten Sie vorerst auch usleep verwenden.
52

Sie können diese plattformübergreifende Funktion verwenden:

#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
}
Bernardo Ramos
quelle
3
Wenn wir nicht haben _POSIX_C_SOURCE >= 199309L, wie im Fall von -ansioder -std=c89, würde ich empfehlen, struct timeval tv; tv.tv_sec = milliseconds / 1000; tv.tv_usec = milliseconds % 1000 * 1000; select(0, NULL, NULL, NULL, &tv);anstelle von zu verwenden usleep(milliseconds * 1000);. Kredit geht hier .
Josh Sanford
Gute Antwort! Beachten Sie, dass hier die nanosleep()Dokumentation ist: man7.org/linux/man-pages/man2/nanosleep.2.html . Das Posten der Dokumentationslinks für jede hier verwendete plattformspezifische Funktion wäre hilfreich.
Gabriel Staples
Beachten Sie auch, dass beim Kompilieren unter gcc -Wall -g3 -std=c11 -o sleep_test sleep_test.c && ./sleep_testLinux Ubuntu mit gcc Version 4.8.4 die folgende Warnung angezeigt wird : warning: implicit declaration of function ‘usleep’ [-Wimplicit-function-declaration]. Die Lösung besteht darin , die folgenden 2 Definitionen ganz oben in Ihren Code einzufügen: 1) #define __USE_POSIX199309und 2) #define _POSIX_C_SOURCE 199309L. Beide sind erforderlich, um den Code ohne Warnungen kompilieren zu können (und um die nanoseconds()verfügbare Funktion zu verwenden).
Gabriel Staples
Verwandte Antwort, die ich gerade gemacht habe: stackoverflow.com/a/55860234/4561887
Gabriel Staples
32

Alternativ zu dem usleep(), was in POSIX 2008 nicht definiert ist (obwohl es bis zu POSIX 2004 definiert wurde und offensichtlich auf Linux und anderen Plattformen mit einer Historie der POSIX-Konformität verfügbar ist), definiert der POSIX 2008-Standard nanosleep():

nanosleep - hochauflösender Schlaf

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

Die nanosleep()Funktion bewirkt, dass der aktuelle Thread von der Ausführung angehalten wird, bis entweder das durch das rqtpArgument angegebene Zeitintervall abgelaufen ist oder ein Signal an den aufrufenden Thread gesendet wird, und seine Aktion besteht darin, eine Signalfangfunktion aufzurufen oder den Prozess zu beenden. Die Unterbrechungszeit kann länger als angefordert sein, da der Argumentwert auf ein ganzzahliges Vielfaches der Schlafauflösung aufgerundet wird oder weil andere Aktivitäten vom System geplant werden. Mit Ausnahme des Falls, durch ein Signal unterbrochen zu werden, darf die Suspendierungszeit jedoch nicht kürzer sein als die von rqtp, gemessen durch die Systemuhr CLOCK_REALTIME.

Die Verwendung der nanosleep()Funktion hat keine Auswirkung auf die Aktion oder Blockierung eines Signals.

Jonathan Leffler
quelle
24

Über den Schlaf hinaus können Sie mit der bescheidenen Auswahl mit NULL-Dateideskriptorsätzen mit einer Genauigkeit von Mikrosekunden und ohne das Risiko von SIGALRMKomplikationen pausieren .

sigtimedwait und sigwaitinfo bieten ein ähnliches Verhalten.

Pilger
quelle
1
"ohne das Risiko von Sigalarm": Welches Risiko und welcher Fall? Schlaf und Schlaf nennen?
Massimo
2
@Massimo, die verknüpfte Spezifikation für usleep enthält mehrere Sätze zum nicht spezifizierten SIGALARM-Verhalten. (Grundsätzlich usleep und Schlaf sind erlaubt über die alte umgesetzt werden Alarmmechanismus, der Sie sichere Nutzung würde komplizieren sich vorstellen kann usleep und SIGALARM. Ich weiß nicht , von jedem modernen System , das es so tut, aber es ist immer noch in der spec.)
Pilcrow
14
#include <unistd.h>

int usleep(useconds_t useconds); //pass in microseconds
Jonathan Leffler
quelle
-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;
}
Odin
quelle
1
Dies wird nicht für Millisekunden schlafen und führt auch zu viel mehr Overhead, was das Timing noch unzuverlässiger macht.
Devolus
Beispiel schläft nicht für Mikrosekunden, und dies ist keine so gute Lösung im Vergleich zur Verwendung von usleep ().
Victor Ocampo