Frage

In der traditionellen Embedded-Programmierung, werden wir eine Verzögerungsfunktion geben etwa so:

for(i=0;i<255;i++)
   for(j=0;j<255;j++);

Nach Ansicht des Mikroprozessors ist dies, wie der Schlaf () Funktion funktioniert?

Gibt es eine Alternative für den Schlaf () Funktion in C?

War es hilfreich?

Lösung

Alternativen hängen, was Sie versuchen zu tun und was OS sind Sie an.

Wenn Sie nur Zeit verschwenden wollen, dann könnten diese helfen:

Bei den meisten Unix-artigen Systemen Sie eine ‚usleep‘ Funktion finden, die mehr oder weniger wie Schlaf mit einem größeren Auflösung. Seien Sie vorsichtig mit, dass man, weil es in der Regel nicht nur für eine Mikrosekunde schlafen kann.

Bei einigen Unix-artigen Systemen kann der ausgewählte Systemaufruf mit alle Datei Deskriptormengen verwendet wird Null, um eine ziemlich genaue Unter zweiten Wartezeit zu erhalten.

Auf Windows-Systemen haben Sie schlafen, die so ziemlich das gleiche, aber eine Anzahl von Millisekunden nehmen.

In einem Multi-Tasking-Betriebssystem kann eine Sleep-Funktion manchmal 0 als Parameter angegeben werden. Dies bewirkt, dass im Allgemeinen die Funktion es die Zeitscheibe aufgeben, aber sofort wieder eingeplant werden, wenn keine andere Aufgabe ist es betriebsbereit.

Andere Tipps

Die Art der Schleife Sie beschreiben, ist ein „busy wait“ genannt. In realen Betriebssystemen Schlaf verursacht keine busy wait; es teilt das Betriebssystem nicht in den Prozess zu planen, bis die Schlafperiode vorüber ist.

Ein gemeinsamer Mechanismus ist ein select() zu verwenden, die aus der Zeit gewährleistet ist, und die Ruhezeit als Timeout angeben:

// Sleep for 1.5 sec
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 500000;
select(0, NULL, NULL, NULL, &tv);

Die select() wird normalerweise verwendet, eine Reihe von Datei-Deskriptoren zu überprüfen und warten, bis mindestens ein bereit ist, I / O auszuführen. Falls keine bereit ist (oder in diesem Fall, wenn keine fds angegeben ist), wird es Zeit aus.

Der Vorteil von select() über einen langen Schleife ist, dass es sehr wenig Ressourcen verbraucht während des Schlafens, während eine geschäftige Schleife um den Prozessor so viel monopolisiert wie durch seine Prioritätsstufe erlaubt.

Sie würden nicht den Code verwenden Sie auf einem Embedded-System schlafen veröffentlicht. Ein anständiger Compiler wäre es ganz zu entfernen, und auch wenn Ihr Compiler nicht entfernt es suboptimal, da den Prozessor in einer engen Schleife ausgeführt wird Energie verbrennen, was ein Problem für Embedded-System ist. Auch Systeme nicht auf Batterie kümmern sich um den Stromverbrauch ausgeführt wird, da niedrigerer Stromverbrauch bedeutet billigere Stromversorgung und Kühlung.

Die Art und Weise Sie dies normalerweise tun ist, Ihre CPU eine Art von IDLE oder SLEEP Anweisungen implementieren wird, verursachen, dass wird es vorübergehend Befehle verarbeiten zu stoppen. Eine externe Interrupt-Leitung mit einer Zeitschaltung verbunden wird den Prozessor wieder nach oben in regelmäßigen Abständen weckt, und die die CPU prüft Punkt zu sehen, ob es genug für lange geschlafen hat, und wenn es nicht geht, wieder einzuschlafen.

//Pseudo code
int start = getTime();
int end = start + sleepTime;

while (getTime() < end) {
       asm("SLEEP");
}

Die genauen Details von Prozessor zu Prozessor variieren. Wenn Sie sich als Prozess ausgeführt werden auf einem OS im Allgemeinen der Schlaf Anruf sagt nur den Scheduler Ihren Prozess auszusetzen, und dann entscheidet der Kernel, ob ein anderer Prozess zu planen oder um die CPU zu schlafen. Außerdem wird der obige Code nicht adequete sein für Echtzeitsysteme, die Frist Garantien wollen, usw. In diesen Fällen müssen Sie die Zeit in der Schleife bekommen, wissen die Dauer der Zeit zu unterbrechen, damit Sie wissen, wenn Sie ou resleep ohne Blasen die Frist, und möglicherweise die Timer-Hardware oder busy wait umprogrammieren.

Sie über „Embedded-Programmierung“ sprechen im OP. Wenn Sie eingebettete Arbeit tun und so etwas wie Schlaf benötigen (), gibt es häufig Hardware-Zähler / Timer zur Verfügung. Diese von der Architektur zur Architektur variieren, so haben Sie einen Blick auf das Datenblatt.

Wenn Sie nicht eingebettet Arbeit zu tun, ich entschuldige mich:)

Wenn Sie for-Schleifen verwenden, sollten Sie besser wissen, was sie zu kompilieren und wie lange diese Anweisungen, um in Ihrer bestimmten Taktgeschwindigkeit, und sicherstellen, dass der CPU läuft Ihre Anweisungen und nichts anderes (dies kann in Embedded-Systemen durchgeführt werden, aber es ist schwierig, da es Interrupts nicht zulässt).

Ansonsten werden Sie nicht sagen können, wie lange gehen nehmen es wirklich.

Am frühen PC-Spiele hatte dieses Problem -. Sie für einen 4.7MHz PC gebaut wurden, und wenn die schnellere Computer kam, waren sie unspielbar

Der beste Weg, ein ‚Schlaf‘ arbeiten kann, ist für die CPU zu wissen, wie spät es zu einem bestimmten Zeitpunkt ist. Nicht unbedingt die tatsächliche Zeit (07.15 Uhr), aber zumindest die relative Zeit (8612 Sekunden seit einem bestimmten Zeitpunkt).

Auf diese Weise kann ein Delta auf die aktuelle Zeit gelten und in einer Schleife warten, bis der Strom + Delta erreicht ist.

Alles, was von der Anzahl CPU-Zyklen beruht inhärent unzuverlässig, da die CPU auf eine andere Aufgabe abgehen kann und Ihre Schleife hängen lassen.

Angenommen, Sie haben eine Memory-Mapped-16-Bit-I / O-Port, den die CPU-Schritte einmal pro Sekunde. Nehmen wir an, auch in Ihrem Embedded-System an Speicherplatz 0x33 es ist, wo Ints sind auch 16 Bit. Eine Funktion namens Schlaf dann wird so etwas wie:

void sleep (unsigned int delay) {
    unsigned int target = peek(0x33) + delay;
    while (peek(0x33) != target);
}

Sie werden feststellen, dass Peek gewährleisten müssen () gibt den Speicherinhalt jedes Mal (so optimierende Compiler verhunzen nicht die Logik) und dass Ihre while-Anweisung läuft mehr als einmal pro Sekunde, so dass Sie das Ziel nicht verpassen , aber diese sind operative Fragen, die ich präsentieren nicht das Konzept beeinflussen.

Es gibt mehr Informationen darüber, wie sleep () funktioniert hier

By the way, ist damit beschäftigt Warte nicht unbedingt für Amateure - obwohl es Prozessor tut brennen, die Sie vielleicht für einen anderen Zweck verwenden. Wenn Sie eine Zeitquelle verwenden, werden Sie auf die Granularität dieser Quelle begrenzt. Z.B. wenn Sie ein 1 ms-Timer haben, und wollen Weg 500 uS, haben Sie ein Problem. Wenn Ihr Embedded-System die Tatsache umgeht, dass man für 500 uSek in einer Schleife Summen würde, das könnte akzeptabel sein. Und selbst wenn Sie einen Timer mit dem gewünschten Granularität haben, müssen Sie auch einen Interrupt aus, dass die Timer zur richtigen Zeit bekommen ... dann ot den Interrupt-Handler versenden ... dann zu Ihrem Code. Manchmal ist eine geschäftige Schleife die zweckmäßigste Lösung. Manchmal.

Busy-Warte für Amateure ist sogar in einem eingebetteten System, eine Echtzeitquelle verwenden.

jeder anständige C-Compiler würde, ohne zusätzliche Arbeit, entfernen Sie den Code vollständig und die Verzögerung würde verschwinden

sleep Schnittstellen tatsächlich mit dem Betriebssystem, in dem Schlaf Prozesse außerhalb der Scheduling-Warteschlange plaziert werden. Ich in der Regel verwenden:

poll(0, 0, milliseconds);

für POSIX-kompatible Systeme. select funktioniert auch für Fenster (sie müssen eine native API haben (wahrscheinlich genannt Sleep) dafür.)

Seite 20 in 'Threading in C #' von Joseph Albahari hat eine interessante Diskussion über diese. Sie können nicht für weniger als 1 ms in .Net schlafen, aber DateTime.Ticks hat eine Körnung von 100 ns (= 0,1 Mikrosekunden) Intervalle. Für meine 5-Achsen-CNC-Steuerung Schritt brauche ich nur für 10 Mikrosekunden zwischen Schrittbefehle pausieren. Ich habe einen Mikro-Controller verwendet, um den bösen Looping zu tun, aber ich denke, es ist OK Hand über einen Prozessor für den Job ist, wenn Sie eine ganze Reihe sowieso hat, den Faden nicht mehr, wenn Sie können. Zumindest immer, es wird nicht das gleiche sein.

#include <Windows.h>

static NTSTATUS(__stdcall *NtDelayExecution)(BOOL Alertable, PLARGE_INTEGER DelayInterval) = (NTSTATUS(__stdcall*)(BOOL, PLARGE_INTEGER)) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtDelayExecution");

static NTSTATUS(__stdcall *ZwSetTimerResolution)(IN ULONG RequestedResolution, IN BOOLEAN Set, OUT PULONG ActualResolution) = (NTSTATUS(__stdcall*)(ULONG, BOOLEAN, PULONG)) GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwSetTimerResolution");




static void SleepShort(float milliseconds) {
    static bool once = true;
    if (once) {
        ULONG actualResolution;
        ZwSetTimerResolution(1, true, &actualResolution);
        once = false;
    }

    LARGE_INTEGER interval;
    interval.QuadPart = -1 * (int)(milliseconds * 10000.0f);
    NtDelayExecution(false, &interval);
}

Ja, es einige undokumentierte Kernel-Funktionen verwendet, aber ehrlich gesagt, ist es viel schneller als die meisten Vorschläge und funktioniert sehr gut, (beachten Sie, es wird auf die CPU-Betrag begrenzt werden, zum Beispiel Mine nur 500 ns schlafen kann (0,5))

in Linux verfügbar usleep (int Mikrosekunden) Nanosleep (...) mehr Präzision siehe Manpages Argumente aufrufen

In einem Unix-Derivat OS, würden Sie wahrscheinlich ein Signal () -Aufruf planen, und Ihr Code würde einfach den Code sperren, bis das Signal ausgelöst wird. Die Signale werden zum Zwecke bestimmt sind, und sie sind sehr einfach und effizient.

einen Versuch ... wirklich dieses Problem zu lösen, das heißt etwas, das (nicht wie die oben genannten Versuche der Antwort) funktioniert lol

Ich habe immer noch diesen Code zu verbessern, um es aus. Ein paar Add-ons sind willkommen.

// Sleep for both Windows and Linux: 
// Too bad? No one proposed you a solution that works? 
// Since Windows has no select.h nor poll.h, an implementation
// is necessary.
//  
// Solutions on boards are often refered to use either select or poll, but ok, what about C (not c++)?
//
/// implementation of poll is destined in this attempt for windows
/// Ideally, you add this part of code to the header of you *.c file, and it might work through...

#ifdef WIN32
#include <time.h>
#include <sys/time.h>
#include <ws2tcpip.h>
#include <Winsock2.h>
#include <windows.h>
/* winsock doesn't feature poll(), so there is a version implemented
 * in terms of select() in mingw.c. The following definitions
 * are copied from linux man pages. A poll() macro is defined to
 * call the version in mingw.c.
 */
#define POLLIN      0x0001    /* There is data to read */
#define POLLPRI     0x0002    /* There is urgent data to read */
#define POLLOUT     0x0004    /* Writing now will not block */
#define POLLERR     0x0008    /* Error condition */
#define POLLHUP     0x0010    /* Hung up */
#define POLLNVAL    0x0020    /* Invalid request: fd not open */
struct pollfd {
  SOCKET fd;        /* file descriptor */
  short events;     /* requested events */
  short revents;    /* returned events */
};

int mingw_poll (struct pollfd *, unsigned int, int);

#define poll(x, y, z)        mingw_poll(x, y, z)
#endif





int mingw_poll(struct pollfd *fds, unsigned int nfds, int timo)
{
    struct timeval timeout, *toptr;
    fd_set ifds, ofds, efds, *ip, *op;
    int i, rc;

    /* Set up the file-descriptor sets in ifds, ofds and efds. */
    FD_ZERO(&ifds);
    FD_ZERO(&ofds);
    FD_ZERO(&efds);
    for (i = 0, op = ip = 0; i < nfds; ++i) {
    fds[i].revents = 0;
    if(fds[i].events & (POLLIN|POLLPRI)) {
        ip = &ifds;
        FD_SET(fds[i].fd, ip);
    }
    if(fds[i].events & POLLOUT) {
        op = &ofds;
        FD_SET(fds[i].fd, op);
    }
    FD_SET(fds[i].fd, &efds);
    } 

    /* Set up the timeval structure for the timeout parameter */
    if(timo < 0) {
    toptr = 0;
    } else {
    toptr = &timeout;
    timeout.tv_sec = timo / 1000;
    timeout.tv_usec = (timo - timeout.tv_sec * 1000) * 1000;
    }

#ifdef DEBUG_POLL
    printf("Entering select() sec=%ld usec=%ld ip=%lx op=%lx\n",
           (long)timeout.tv_sec, (long)timeout.tv_usec, (long)ip, (long)op);
#endif
    rc = select(0, ip, op, &efds, toptr);
#ifdef DEBUG_POLL
    printf("Exiting select rc=%d\n", rc);
#endif

    if(rc <= 0)
    return rc;

    if(rc > 0) {
        for (i = 0; i < nfds; ++i) {
            int fd = fds[i].fd;
        if(fds[i].events & (POLLIN|POLLPRI) && FD_ISSET(fd, &ifds))
            fds[i].revents |= POLLIN;
        if(fds[i].events & POLLOUT && FD_ISSET(fd, &ofds))
            fds[i].revents |= POLLOUT;
        if(FD_ISSET(fd, &efds))
            /* Some error was detected ... should be some way to know. */
            fds[i].revents |= POLLHUP;
#ifdef DEBUG_POLL
        printf("%d %d %d revent = %x\n", 
                FD_ISSET(fd, &ifds), FD_ISSET(fd, &ofds), FD_ISSET(fd, &efds), 
                fds[i].revents
        );
#endif
        }
    }
    return rc;
}

ich die Funktion in diesem Beitrag nicht gefunden ( http: //cboard.cprogramming.com/c-programming/111229-how-use-sleep-function.html ) und es funktioniert:

#include <stdio.h>
#include <windows.h>

int main()
{
    puts("Hello \n");
    /* in windows.h is declared the Sleep (upper S) function and it takes time in 
miliseconds */
    Sleep(3000);
    puts("World \n");
    return 0;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top