Zeitverzögerung in c implementieren

Lesezeit: 10 Minuten

Benutzer-Avatar
Entwickler

Ich weiß nicht genau, wie ich eine Suche danach formulieren soll.. also hatte ich kein Glück, etwas zu finden.. :S

Ich muss eine Zeitverzögerung in C implementieren.

Zum Beispiel möchte ich etwas tun, dann warte, sagen wir, 1 Minute, und mache dann weiter.

Hat das Sinn gemacht? Kann mir jemand helfen?

Benutzer-Avatar
paxdiablo

In Standard-C (C99) können Sie verwenden time() um dies zu tun, so etwas wie:

#include <time.h>
:
void waitFor (unsigned int secs) {
    unsigned int retTime = time(0) + secs;   // Get finishing time.
    while (time(0) < retTime);               // Loop until it arrives.
}

Das setzt übrigens voraus time() gibt einen Auflösungswert von 1 Sekunde zurück. Ich glaube nicht, dass dies vom Standard vorgeschrieben ist, also müssen Sie sich möglicherweise darauf einstellen.


Zur Verdeutlichung ist dies die nur Art und Weise, die mir bekannt ist, dies mit ISO C99 zu tun (und die Frage ist mit nichts anderem als “C” gekennzeichnet, was normalerweise bedeutet, dass tragbare Lösungen wünschenswert sind, obwohl natürlich immer noch herstellerspezifische Lösungen angegeben werden können).

Auf jeden Fall, wenn Sie auf einer Plattform sind, die einen effizienteren Weg bietet, benutze es. Wie mehrere Kommentare angedeutet haben, kann es bei einer engen Schleife wie dieser zu spezifischen Problemen in Bezug auf die CPU-Auslastung und die Akkulaufzeit kommen.

Jedes anständige Time-Slicing-Betriebssystem wäre in der Lage, die dynamische Priorität einer Aufgabe, die kontinuierlich ihre volle Zeitscheibe verwendet, fallen zu lassen, aber die Batterieleistung könnte problematischer sein.

C spezifiziert jedoch nichts über die Betriebssystemdetails in einer gehosteten Umgebung, und diese Antwort gilt nur für ISO C und ISO C (also keine Verwendung von sleep, selectWin32-API-Aufrufe oder ähnliches).

Und behalte das im Hinterkopf Posix sleep kann durch Signale unterbrochen werden. Wenn du sind Um diesen Weg zu gehen, müssen Sie Folgendes tun:

int finishing = 0; // set finishing in signal handler 
                   // if you want to really stop.

void sleepWrapper (unsigned int secs) {
    unsigned int left = secs;
    while ((left > 0) && (!finishing)) // Don't continue if signal has
        left = sleep (left);           //   indicated exit needed.
}

  • Ja, es wird eine CPU-Last geben, aber jedes anständige Betriebssystem (unter der Annahme von präventivem Multitasking) erkennt dies und senkt die dynamische Priorität entsprechend. Und wenn dies nicht der Fall ist, spielt die CPU-Last keine Rolle (wenn es sich um kooperatives Multitasking handelt, sollten Sie sich vielleicht eine yield Funktion). Der Grund, warum ich dies gepostet habe, ist, dass es keine tragbare Methode für ISO-C gibt und die Frage nur mit “C” (sleepobwohl nützlich, ist nicht Standard).

    – paxdiablo

    14. Oktober 2010 um 6:04 Uhr


  • @paxdiablo: Nein, eigentlich nicht … Die Taktfrequenz einer der CPUs steigt auf 100% Prozent. Und die CPU-Last spielt eine Rolle, besonders wenn Sie sich auf einem Laptop befinden, wenn die CPU maximal ausgelastet ist, erzeugt sie Wärme, und Wärme verkürzt die Lebensdauer des Computers. Auf einem alten stationären Gerät spielt das wahrscheinlich keine Rolle, so handhabt Windows es (eine Endlosschleife, die nichts tut, wenn es nichts zu tun gibt). Ich schätze, dass heutige Betriebssysteme fortschrittliche Energiespartechniken verwenden, aber ich weiß, dass der Linux-Kernel eine hlt-Anweisung ausgegeben hat, genauso wie ich, als ich 12 war.

    – Frank

    14. Oktober 2010 um 6:17 Uhr

  • sleep( sec ) ist anscheinend ein ISO/IEC 9945-1:1990 (POSIX 1) Standard, es ist nur Microsoft, das seinen Weg geht, während der Rest der Welt einen Weg tut …

    – Frank

    14. Oktober 2010 um 6:23 Uhr


  • @Frank, wenn Sie sagen, dass die dynamische Priorität von Windows nicht angepasst wird, liegen Sie falsch. Bei Threads, die die CPU freiwillig abgeben, werden die dynamischen Prioritäten erhöht. Die Prioritäten derjenigen, die nach Verwendung ihrer gesamten Zeitscheibe gezwungen werden, werden reduziert (wenn auch nicht unter ihre Grundlinie, aus dem Gedächtnis). Dies wird tendenziell gut erzogene Apps gegenüber anderen bevorzugen. Sie haben Recht, dass es immer noch CPU verbraucht, aber noch einmal, wenn Sie ein Betriebssystem verwenden, das dies zulässt sleep Um Ihren Prozess in eine Warteschlange zu stellen (und die CPU anzuhalten, wenn nur die Leerlaufaufgabe ausgeführt wird), verwenden Sie es. Es ist immer noch nicht Standard.

    – paxdiablo

    14. Oktober 2010 um 6:26 Uhr

  • @Frank, denke ich volatile sig_atomic_t finishing ist die richtige Deklaration für eine Variable, die von einem Signalhandler und dem Haupt-Thread gemeinsam genutzt wird. Ich wollte nur darauf hinweisen, dass es oft äußere Auflagen gibt, die eingehalten werden müssen…

    – RBerteig

    14. Oktober 2010 um 8:35 Uhr

Benutzer-Avatar
Frank

So können Sie dies auf den meisten Desktop-Systemen tun:

#ifdef _WIN32
    #include <windows.h>
#else
    #include <unistd.h>
#endif

void wait( int seconds )
{   // Pretty crossplatform, both ALL POSIX compliant systems AND Windows
    #ifdef _WIN32
        Sleep( 1000 * seconds );
    #else
        sleep( seconds );
    #endif
}

int
main( int argc, char **argv)
{
    int running = 3;
    while( running )
    {   // do something
        --running;
        wait( 3 );
    }
    return 0; // OK
}

So können Sie es auf einem Mikrocomputer / Prozessor ohne Timer machen:

int wait_loop0 = 10000;
int wait_loop1 = 6000;

// for microprocessor without timer, if it has a timer refer to vendor documentation and use it instead.
void
wait( int seconds )
{   // this function needs to be finetuned for the specific microprocessor
    int i, j, k;
    for(i = 0; i < seconds; i++)
    {
        for(j = 0; j < wait_loop0; j++)
        {
            for(k = 0; k < wait_loop1; k++)
            {   // waste function, volatile makes sure it is not being optimized out by compiler
                int volatile t = 120 * j * i + k;
                t = t + 5;
            }
        }
    }
}

int
main( int argc, char **argv)
{
    int running = 3;
    while( running )
    {   // do something
        --running;
        wait( 3 );
    }
    return 0; // OK
}

Die Waitloop-Variablen müssen fein abgestimmt werden, diese haben für meinen Computer ziemlich gut funktioniert, aber die Sache mit der Frequenzskala macht es für ein modernes Desktop-System sehr ungenau; Verwenden Sie es dort also nicht, es sei denn, Sie sind absolut nackt und tun solche Sachen nicht.

  • Sie gehen eindeutig von einem Betriebssystem mit nützlichen Systemaufrufen aus, und die eigentliche Frage erwähnt nur Standard-C, dem, wie Pax betont, jegliche Art von Verzögerungsanrufen fehlt. Auf Plattformen ohne Betriebssystem läuft sehr viel C-Code. Obwohl einige Mechanismen ähnlich sind sleep() ist auf solchen Plattformen oft eine gute Sache, es wird von keinem der C-Standards verlangt.

    – RBerteig

    14. Oktober 2010 um 8:04 Uhr


  • Ich dachte daran, darüber zu schreiben, wie man es auf Mikroprozessoren ohne ein Betriebssystem macht, aber ich fühlte mich nicht ganz danach. Nicht wirklich mein Fachgebiet.

    – Frank

    14. Oktober 2010 um 8:24 Uhr

  • @Frank, Auch ohne Betriebssystem haben Sie oft einen in Hardware implementierten Zähler, der Zyklen einer Uhr zählt. Eine Möglichkeit besteht also darin, diesen Zähler zu lesen, einen zukünftigen Wert vorherzusagen und in einer Schleife zu drehen, bis der Zähler den Wert erreicht. Das funktioniert für Wartezeiten, die kurz genug sind, damit der Zähler während des Wartens nicht mehr als einmal umbricht. Bei kleinen CPUs muss man manchmal auf manuell abgestimmte Schleifen zurückgreifen, bei denen man genau weiß, wie viele Zyklen pro Iteration verbraucht werden. Es gibt immer einen Weg, aber es ist vielleicht nicht schön.

    – RBerteig

    14. Oktober 2010 um 8:40 Uhr


  • Genau, es muss nicht immer schön sein. Aber ich frage mich, gibt es keine Mikrocomputer, bei denen Sie einen Interrupt setzen und hlt ausgeben können, um Strom zu sparen?

    – Frank

    14. Oktober 2010 um 8:48 Uhr

  • @Frank: Manche haben es. Zum Beispiel hat PIC32MX 2 Arten von Timern. Typ A hat einen eigenen Oszillator, B nicht. Beide erlauben Ihnen, den Prescaler auszuwählen.

    – jweyrich

    14. Oktober 2010 um 9:04 Uhr


Prüfen sleep(3) Manpage oder MSDN für Schlaf

Benutzer-Avatar
Wilhelm Grau

Obwohl viele Implementierungen die time Funktion gibt die aktuelle Zeit in zurück SekundenEs gibt keine Garantie dass jede Implementierung dies tun wird (z. B. können einige zurückkehren Millisekunden statt Sekunden). Daher ist eine tragbarere Lösung die Verwendung von difftime Funktion.

difftime wird garantiert durch die C-Standard um den Zeitunterschied in zurückzugeben Sekunden zwischen zwei time_t Werte. Als solches können wir eine portable Zeitverzögerungsfunktion schreiben, die auf allen konformen Implementierungen von läuft C-Standard.

#include <time.h>

void delay(double dly){
    /* save start time */
    const time_t start = time(NULL);

    time_t current;
    do{
        /* get current time */
        time(&current);

        /* break loop when the requested number of seconds have elapsed */
    }while(difftime(current, start) < dly);
}

Eine Einschränkung mit der time und difftime Funktionen ist, dass die C-Standard gibt niemals eine Granularität an. Die meisten Implementierungen haben eine Granularität von eine Sekunde. Während dies für anhaltende Verzögerungen in Ordnung ist mehrere Sekundenkann unsere Verzögerungsfunktion zu lange auf Verzögerungen warten unter einer Sekunde.

Es gibt eine portable Standard-C-Alternative: die clock Funktion.

Das clock Die Funktion gibt die beste Annäherung der Implementierung an die Prozessorzeit zurück, die das Programm seit dem Beginn einer implementierungsdefinierten Ära verwendet hat, die sich nur auf den Programmaufruf bezieht. Um die Zeit in Sekunden zu bestimmen, wird der von der zurückgegebene Wert verwendet clock Funktion sollte durch den Wert des Makros dividiert werden CLOCKS_PER_SEC.

Das clock Funktionslösung ist unserer ziemlich ähnlich time Funktionslösung:

#include <time.h>

void delay(double dly){
    /* save start clock tick */
    const clock_t start = clock();

    clock_t current;
    do{
        /* get current clock tick */
        current = clock();

        /* break loop when the requested number of seconds have elapsed */
    }while((double)(current-start)/CLOCKS_PER_SEC < dly);
}

In diesem Fall gibt es einen ähnlichen Vorbehalt wie bei time und difftime: die Granularität der clock Funktion bleibt der Implementierung überlassen. Beispielsweise Maschinen mit 32-Bit-Werten für clock_t mit Auflösung in Mikrosekunden kann dazu führen, dass der von zurückgegebene Wert umgebrochen wird clock nach 2147 Sekunden (ca. 36 Minuten).

Ziehen Sie daher die Verwendung von in Betracht time und difftime Implementierung der Verzögerungsfunktion für dauerhafte Verzögerungen mindestens eine Sekundeund die clock Umsetzung für dauerhafte Verzögerungen unter einer Sekunde.

Ein letztes Wort der Warnung: clock kehrt zurück Prozessorzeit statt Kalenderzeit; clock entspricht möglicherweise nicht der tatsächlich verstrichenen Zeit (z. B. wenn der Prozess schläft).

Bei Verspätungen ab einer Minute sleep() ist eine gute Wahl.

Wenn Sie eines Tages bei Verzögerungen von weniger als einer Sekunde pausieren möchten, sollten Sie darüber nachdenken poll() mit Zeitüberschreitung.

Beide sind POSIX.

Es gibt keine sleep() Funktionen in der C-Standardbibliothek vor C11, aber POSIX bietet einige Optionen.

Die POSIX-Funktion sleep() (unistd.h) nimmt an unsigned int Argument für die gewünschte Schlafdauer in Sekunden. Obwohl dies keine Standardbibliotheksfunktion ist, ist sie weit verbreitet, und glibc scheint sie zu unterstützen, selbst wenn mit strengeren Einstellungen wie kompiliert wird --std=c11.

Die POSIX-Funktion nanosleep() (time.h) nimmt zwei Zeiger auf timespec Strukturen als Argumente und bietet eine feinere Kontrolle über die Schlafdauer. Das erste Argument gibt die Verzögerungsdauer an. Wenn das zweite Argument kein Nullzeiger ist, enthält es die verbleibende Zeit, wenn der Aufruf von einem Signalhandler unterbrochen wird.

Programme, die die verwenden nanosleep() Funktion muss möglicherweise a enthalten Feature-Test-Makro um zu kompilieren. Das folgende Codebeispiel wird auf meinem Linux-System ohne ein Feature-Test-Makro nicht kompiliert, wenn ich einen typischen Compiler-Aufruf verwende gcc -std=c11 -Wall -Wextra -Wpedantic.

POSIX hatte einmal eine usleep() Funktion (unistd.h), die eine benötigte useconds_t -Argument zur Angabe der Schlafdauer in Mikrosekunden. Diese Funktion erforderte auch ein Funktionstestmakro, wenn sie mit strengen Compilereinstellungen verwendet wurde. Ach, usleep() wurde mit POSIX.1-2001 obsolet und sollte nicht mehr verwendet werden. Es wird empfohlen, dass nanosleep() jetzt verwendet werden statt usleep().

#define _POSIX_C_SOURCE  199309L     // feature test macro for nanosleep()

#include <stdio.h>
#include <unistd.h>    // for sleep()
#include <time.h>      // for nanosleep()

int main(void)
{
    // use unsigned sleep(unsigned seconds)
    puts("Wait 5 sec...");
    sleep(5);

    // use int nanosleep(const struct timespec *req, struct timespec *rem);
    puts("Wait 2.5 sec...");
    struct timespec ts = { .tv_sec = 2,          // seconds to wait
                           .tv_nsec = 5e8 };     // additional nanoseconds
    nanosleep(&ts, NULL);
    puts("Bye");

    return 0;
}

Nachtrag:

C11 hat den Header threads.h Bereitstellung thrd_sleep()die identisch mit funktioniert nanosleep(). GCC wurde nicht unterstützt threads.h bis 2018, mit der Veröffentlichung von glibc 2.28. Es war im Allgemeinen schwierig, Implementierungen mit Unterstützung für zu finden threads.h (Clang hat es lange nicht unterstützt, aber ich bin mir nicht sicher über den aktuellen Stand der Dinge dort). Sie müssen diese Option mit Vorsicht verwenden.

Benutzer-Avatar
Waffel-Paradoxon

Versuchen sleep(int number_of_seconds)

1386190cookie-checkZeitverzögerung in c implementieren

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy