Frage

Unter Windows habe ich ein Problem, das ich nie auf Unix begegnet. Das ist, wie ein Faden für weniger als eine Millisekunde zu schlafen. Auf Unix haben Sie in der Regel eine Reihe von Entscheidungen (Schlaf, usleep und Nanosleep) an Ihre Bedürfnisse anzupassen. Unter Windows gibt es jedoch nur Schlaf mit Millisekunden Granularität.

Unter Unix kann ich die Verwendung des select Systemaufruf verwenden, um eine Mikrosekunde Schlaf zu schaffen, das ist ziemlich einfach:

int usleep(long usec)
{
    struct timeval tv;
    tv.tv_sec = usec/1000000L;
    tv.tv_usec = usec%1000000L;
    return select(0, 0, 0, 0, &tv);
}

Wie kann ich das gleiche auf Windows erreichen?

War es hilfreich?

Lösung 18

Unter Windows die Verwendung von select zwingt Sie die Winsock Bibliothek, die wie dies in der Anwendung initialisiert werden muss:

WORD wVersionRequested = MAKEWORD(1,0);
WSADATA wsaData;
WSAStartup(wVersionRequested, &wsaData);

Und dann die Auswahl werden Sie nicht zulassen, dass ohne Steckdose genannt werden, so dass Sie ein wenig mehr zu tun haben, einen Sekundenschlaf-Methode zu erstellen:

int usleep(long usec)
{
    struct timeval tv;
    fd_set dummy;
    SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    FD_ZERO(&dummy);
    FD_SET(s, &dummy);
    tv.tv_sec = usec/1000000L;
    tv.tv_usec = usec%1000000L;
    return select(0, 0, 0, &dummy, &tv);
}

All diese erstellt usleep Methoden zurückkehren Null, wenn erfolgreich und Nicht-Null-Fehler.

Andere Tipps

Dies deutet auf ein Fehl Verständnis von Schlaf-Funktionen. Der Parameter Sie übergeben ein Minimum Zeit zum Schlafen. Es gibt keine Garantie, dass der Faden nach genau festgelegten Zeit aufwacht. In der Tat tun Fäden nicht ‚aufwachen‘ überhaupt, sondern eher für die Ausführung durch den Scheduler gewählt. Der Scheduler kann wählen, um viel länger warten als die angeforderte Schlafdauer einen Thread zu aktivieren, vor allem, wenn ein anderen Thread zu diesem Zeitpunkt noch aktiv ist.

Wie Joel sagt, kann man nicht sinnvoll ‚Schlaf‘ (das heißt geplanten CPU verzichten) für eine solche kurze Zeiträume. Wenn Sie für einige kurze Zeit verzögert werden sollen, dann müssen Sie sich drehen, immer wieder eine entsprechend hochauflösende Timer überprüft (zB der ‚Performance-Timer‘) und in der Hoffnung, dass etwas von hohen Priorität nicht nicht vorgreift Sie trotzdem.

Wenn Sie wirklich kümmern uns um genaue Verzögerungen von so kurzer Zeit, sollten Sie nicht mit Windows werden.

Mit dem hochauflösende Timer zur Verfügung in Winmm.lib. Siehe diese für ein Beispiel.

Ja, müssen Sie Ihre OS‘Zeit quantums verstehen. Unter Windows werden Sie nicht einmal 1 ms Auflösung mal bekommen, wenn Sie die Zeit Quanten zu 1ms ändern. (Zum Beispiel mittels timebeginperiod () / timeEndPeriod ()) Das wird noch nicht wirklich etwas garantieren. Selbst eine kleine Last oder eine einzelne crappy Gerätetreiber wird alles abwerfen.

SetThreadPriority () hilft, aber es ist ziemlich gefährlich. Bad Gerätetreiber können Sie immer noch ruinieren.

Sie benötigen eine ultra-gesteuerte Computerumgebung diese hässliche Sache Arbeit überhaupt zu machen.

#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 nutzt einige undokumentierte Kernel-Funktionen, aber es funktioniert sehr gut, ich benutze SleepShort (0,5); in einigen meiner threds

Wenn Sie so viel Granularität wollen Sie an der falschen Stelle sind (im User-Space).

Denken Sie daran, dass, wenn Sie im User-Space Ihre Zeit sind nicht immer präzise.

Der Scheduler kann den Thread (oder app) beginnen und es planen, so dass Sie von den OS-Scheduler abhängig.

Wenn Sie etwas suchen, genau Sie haben zu gehen: 1) im Kernel-Raum (wie Treiber) 2) Wählen Sie ein RTOS.

Wie auch immer, wenn Sie für einige Granularität suchen (aber das Problem mit User-Space erinnern) schauen zu Queryperformancecounter Funktion und Queryperformance Funktion in MSDN.

Wie mehrere Leute haben darauf hingewiesen, Schlaf und andere verwandte Funktionen standardmäßig sind abhängig von dem „Systemtick“. Dies ist die minimale Zeiteinheit zwischen O Aufgaben; der Scheduler, zum Beispiel, wird nicht schneller als diese ausgeführt werden. Selbst mit einem Echtzeit-Betriebssystem, ist das System Zecke nicht in der Regel weniger als 1 ms. Während es abstimmbar ist, hat dies Auswirkungen auf das gesamte System, nicht nur Schlaf-Funktionalität, weil Ihr Scheduler häufiger ausgeführt werden, und möglicherweise den Aufwand für Ihr Betriebssystem (die Zeit für den Scheduler Erhöhung zu laufen, gegen Menge Zeit eine Aufgabe ausgeführt werden kann).

Die Lösung hierfür ist ein externes, Hochgeschwindigkeits-Taktgerät zu verwenden. Die meisten Unix-Systeme ermöglicht es Ihnen, Ihre Timer und solchen verschiedenen Takt zu spezifizieren, zu verwenden, wie zum Standardsystemtakt gegenüber.

Was für, dass Sie warten, erfordert eine solche Präzision? Im Allgemeinen, wenn Sie auf Notwendigkeit , dass Niveau der Genauigkeit bestimmen (zum Beispiel wegen einer Abhängigkeit von einer externen Hardware) Sie auf der falschen Plattform sind und in einem Echtzeit-Betriebssystem aussehen sollten.

Ansonsten sollten Sie in Erwägung ziehen, wenn es ein Ereignis ist, können Sie synchronisieren auf, oder im schlimmsten Fall nur damit beschäftigt, die CPU warten und den hohen Leistungsindikatoren API verwenden, um die verstrichene Zeit zu messen.

Im allgemeinen wird ein Schlaf wird mindestens bis zur nächsten Systemunterbrechung dauern auftritt. Dies ist jedoch hängt von den Einstellungen der Multimedia-Timer-Ressourcen. Er kann sich auf etwas in der Nähe gesetzt werden 1 ms ermöglicht einig Hardware auch bei Interrupt-Perioden von 0,9765625 ( ActualResolution zur Verfügung gestellt von NtQueryTimerResolution laufen 0,9766 zeigen, aber das ist eigentlich falsch. Sie können einfach nicht die richtige Nummer in die put ActualResolution Format. Es ist 0.9765625ms bei 1024 Interrupts pro Sekunde).

Es gibt eine Ausnahme wich uns aus der Tatsache entweichen lässt, dass es unmöglich sein kann, für weniger als die Unterbrechungsperiode zu schlafen: Es ist die berühmte Sleep(0) ist. Dies ist ein sehr leistungsfähiges Werkzeug und es wird so oft wie es nicht verwendet wird, sollte! Es verzichtet auf die Erinnerung an die Zeitscheibe des Threads. Auf diese Weise der Faden wird aufhören, bis der Scheduler den Faden zwingt wieder cpu Service zu erhalten. Sleep(0) ist ein asynchroner Dienst, wird der Anruf die Scheduler zwingen, unabhängig von einem Interrupt reagieren zu können.

Eine zweite Möglichkeit ist die Verwendung eines waitable object. Eine Wartefunktion wie WaitForSingleObject() kann auf ein Ereignis warten. Um ein Thread schläft für jede Zeit zu haben, auch Zeiten im Mikrosekunden Regime, muss der Thread einige Service-Thread die Einrichtung, die ein Ereignis auf der gewünschten Verzögerung erzeugt. Der „schlafende“ Thread-Setup dieses Thema und dann in der Wartefunktion, bis der Dienst Thread pausiert gesetzt das Ereignis signalisiert.

Auf diese Weise jeder Thread kann „Schlaf“ oder für jederzeit warten. Der Service Thread kann von großer Komplexität sein und es kann systemweite Dienste wie zeitlich Ereignisse an Mikrosekunde Auflösung bieten. Jedoch kann Mikrosekunde Auflösung des Dienstthread zwingen für höchstens eine Unterbrechungsperiode (~ 1ms) auf einem hochauflösenden Zeitdienst zu spinnen. Wenn darauf geachtet wird, kann dies läuft sehr gut, besonders auf Multi-Prozessor-oder Multi-Core-Systemen. A ein ms Spin verletzt nicht wesentlich auf Multi-Core-System, wenn die Affinitätsmaske für den anrufenden Faden und der Service-Thread werden sorgfältig behandelt werden.

-Code, eine Beschreibung und Prüfung kann bei dem Windows-Timestamp-Projekt besucht werden

Ich habe das gleiche Problem und nichts scheint ein ms schneller zu sein als auch die Sleep (0). Mein Problem ist die Kommunikation zwischen einem Client und einer Server-Anwendung, wo ich die _InterlockedExchange Funktion verwenden, um ein Bit zu testen und zu setzen und dann I Sleep (0).

Ich muß wirklich auf diese Weise Tausende von Operationen pro Sekunde ausführen und es so schnell nicht funktioniert wie geplant.

Da hat ich einen Thin Client mit dem Benutzer zu tun, was wiederum einen Agenten aufruft, die dann im Gespräch mit einem Faden, werde ich bald bewegen, um den Faden mit dem Agenten zu verbinden, so dass keine Ereignis-Schnittstelle erforderlich sein wird.

Nur um euch eine Idee, wie langsam dieser Schlaf ist, lief ich einen Test für 10 Sekunden eine leere Schleife durchführt (so etwas wie 18 Millionen Schleifen bekommen), während mit der Veranstaltung an Ort und Stelle bekam ich nur 180.000 Schleifen. Das heißt, 100-mal langsamer!

Eigentlich diese usleep Funktion wird ein großes Speicher / Ressourcen-Leck verursachen. (Je nachdem, wie oft genannt wird)

Mit dieser korrigierte Version (sorry kann nicht bearbeiten?)

bool usleep(unsigned long usec)
{
    struct timeval tv;
    fd_set dummy;
    SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    FD_ZERO(&dummy);
    FD_SET(s, &dummy);
    tv.tv_sec = usec / 1000000ul;
    tv.tv_usec = usec % 1000000ul;
    bool success = (0 == select(0, 0, 0, &dummy, &tv));
    closesocket(s);
    return success;
}

Versuchen Sie es mit SetWaitableTimer ...

Versuchen Sie boost :: xtime und timed_wait ()

hat Nanosekundengenauigkeit.

Verwenden Sie einfach Sleep (0). 0 ist deutlich weniger als eine Millisekunde. Nun, das klingt komisch, aber ich meine es ernst. Sleep (0) teilt Windows mit, dass Sie nichts haben jetzt zu tun, sondern, dass Sie so bald dachten wollen werden, da der Scheduler wieder läuft. Und da offensichtlich kann der Faden nicht vor dem Scheduler Ausführung geplant wird selbst läuft, ist dies die kürzeste Verzögerung möglich.

Beachten Sie, dass Sie in einer Mikrosekunde Nummer Ihres usleep passieren können, aber so tut Leere usleep (__ int64 t) {Sleep (t / 1000); } -. Keine Garantien tatsächlich diese Zeit schlafen

Sleep-Funktion, die Art und Weise weniger als eine Millisekunde-vielleicht ist

Ich fand, dass der Schlaf (0) für mich gearbeitet. Auf einem System mit einer in der Nähe von 0% Belastung der CPU in Task-Manager, schrieb ich ein einfaches Konsolenprogramm und den Schlaf (0) Funktion für eine konsistente 1-3 Mikrosekunden geschlafen, die als eine Millisekunde Weise weniger ist.

Aber aus den oben genannten Antworten in diesem Thread, ich weiß, dass die Menge Schlaf (0) schläft viel mehr wild als dies auf Systeme mit einer großen CPU-Last variieren kann.

Aber wie ich es verstehe, sollte die Schlaffunktion nicht als Timer verwendet werden. Es sollte das Programm benutzen um das geringste Prozentsatz des CPU wie möglich und führen Sie so oft wie möglich verwendet werden. Für meine Zwecke, wie zum Beispiel ein Geschoss über den Bildschirm in einem Videospielen viel schneller als ein Pixel eine Millisekunde zu bewegen, schlafen (0) funktioniert, denke ich.

Sie würden nur sicherstellen, dass die Ruhezeit als die größte Menge an Zeit, Art und Weise kleiner ist es schlafen würde. Sie haben nicht den Schlaf als Timer verwenden, sondern nur das Spiel die minimale Menge an CPU-Prozentsatz möglich nutzen zu machen. Sie würden eine separate Funktion verwenden, die nichts Schlaf tun muss, ist, kennen zu lernen, wenn eine bestimmte Menge an Zeit vergangen ist und dann über den Bildschirm zu einer Zeit, von sagen wir 1 / 10tel einer Millisekunde oder 100 Mikrosekunden, das Projektil ein Pixel verschieben .

Der Pseudo-Code wäre so etwas wie dies geht.

while (timer1 < 100 microseconds) {
sleep(0);
}

if (timer2 >=100 microseconds) {
move projectile one pixel
}

//Rest of code in iteration here

weiß ich die Antwort nicht für fortgeschrittene Themen oder Programme arbeiten, aber kann für einige oder viele Programme arbeiten.

Wenn Ihr Ziel ist es, „warten auf eine sehr kurze Zeit“ , weil Sie ein spinwait tun, dann gibt es zunehmende warten Sie ausführen können.

void SpinOnce(ref Int32 spin)
{
   /*
      SpinOnce is called each time we need to wait. 
      But the action it takes depends on how many times we've been spinning:

      1..12 spins: spin 2..4096 cycles
      12..32: call SwitchToThread (allow another thread ready to go on time core to execute)
      over 32 spins: Sleep(0) (give up the remainder of our timeslice to any other thread ready to run, also allows APC and I/O callbacks)
   */
   spin += 1;

   if (spin > 32)
      Sleep(0); //give up the remainder of our timeslice
   else if (spin > 12)
      SwitchTothread(); //allow another thread on our CPU to have the remainder of our timeslice
   else
   {
      int loops = (1 << spin); //1..12 ==> 2..4096
      while (loops > 0)
         loops -= 1;
   }
}

Also, wenn Ihr Ziel tatsächlich ist, zu warten nur für ein bisschen , können Sie so etwas wie verwenden:

int spin = 0;
while (!TryAcquireLock()) 
{ 
   SpinOne(ref spin);
}

Die Tugend ist hier, dass wir länger jedes Mal warten, schließlich vollständig schlafen gehen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top