2016-03-02 4 views
9

wird das folgende Stück Code Lassen Sie haben, dass einfach die Dauer von std::this_thread::sleep_for mit 20ms genannt misst: wie mit Toolset v120 std :: this_thread :: sleep_for schläft kürzer als in VS2015 erwartet

#include <iostream> 
#include <chrono> 
#include <thread> 

using namespace std; 
using namespace std::chrono; 

int main() 
{ 
    for (int i = 0; i < 20; i++) 
    { 
     auto start = steady_clock::now(); 
     this_thread::sleep_for(milliseconds(20)); 
     auto end = steady_clock::now(); 
     duration<double, milli> elapsed = end - start; 
     cout << "Waited " << elapsed.count() << " ms\n"; 
    } 
} 

Sobald er ausgeführt wird kompiliert (VS2013 ist) bekomme ich Ergebnisse wie erwartet, das heißt:

Waited 20.0026 ms 
Waited 20.0025 ms 
Waited 20.0025 ms 
Waited 20.0026 ms 
Waited 20.0025 ms 
Waited 20.0025 ms 
Waited 20.0026 ms 
Waited 20.0025 ms 
Waited 20.0025 ms 
Waited 20.0026 ms 

aber wenn sie mit VS2015 des Toolset v140 laufen, sind die Ergebnisse etwas überraschend und nicht respektieren das Versprechen von beiden msdn und cppreference.comsleep_for Beschreibungen (dass sleep_for blockiert die Ausführung des aktuellen Thread für mindestens der angegebenen sleep_duration). Sie sind wie folgt:

Waited 19.7793 ms 
Waited 19.9415 ms 
Waited 19.6056 ms 
Waited 19.9687 ms 
Waited 19.608 ms 
Waited 19.589 ms 
Waited 20.5435 ms 
Waited 19.5669 ms 
Waited 19.6802 ms 
Waited 19.5381 ms 

Wie seine möglich und wie kann ich VS2015 die machen sleep_for schlafen mindestens so lange wie erwartet?

Grüße, Dawid

EDIT:

Wie gewünscht sind meine Einstellungen und OS Details sind:
OS:

  • Windows 7 Professional 64-Bit-

  • von Visual Studios: 2010 Ultimate 2013 Gemeinschafts 2015 Professional mit einem Update 1

Compiler-Einstellungen:

  • Standardeinstellungen für Win32-Konsolenanwendung,

  • einem Debug und Freigabekonfigurationen,

  • beliebige x86 und x64 Zielplattform Archit ectures

+0

Ich verwende 'sleep_until()' in einer Schleife im Falle eines frühen Aufwachens. Ich denke, dass frühes Aufwachen nicht passieren sollte, aber zumindest auf GCC Linux scheint ein frühes Aufwachen immer dann zu passieren, wenn der Prozess ein Signal erhält (offensichtlich nicht Ihr Problem hier). – Galik

+0

Ich sehe nicht die gleichen Ergebnisse lokal oder z. auf http://rextester.com/l/cpp_online_compiler_visual (es verwendet auch VS2015). Erwägen Sie, weitere Informationen über Ihre genauen Compilereinstellungen, Zielarchitektur, Hostbetriebssystem, Maschinenspezifikationen usw. hinzuzufügen. – Yirkha

+0

@Yirkha: Ich habe mehr Details über meine Bedingungen in der Beschreibung hinzugefügt. Wie für Ihre Ergebnisse - es wird aussehen wie kleine Unterschiede in meinem System zu jagen. – dawid

Antwort

8

Die sleep_for() Methode Implementierung in VS2015 enthält bereits eine Schleife um den Sleep() Systemaufruf, so dass alle unechten Wakeups werden es keinen Einfluss auf - siehe _Thrd_sleep() in VC\crt\src\stl\cthread.c.


Die Ursache Ihrer Probleme ist wahrscheinlich die Tatsache, dass sleep_for() und sleep_until() ruft sie nach innen, sind chrono::system_clock mit der Zeit zu berechnen, zu warten, aber Sie messen die Zeit mit chrono::steady_clock.

Beide Timer können die gleiche Genauigkeit haben, aber nicht unbedingt die gleiche Genauigkeit. Dann kann es passieren, dass die system_clock ein wenig nacheilt, während steady_clock bereits ein paar μs voraus ist, und die Wartezeit, die mit system_clock berechnet wird, ist tatsächlich kürzer als angefordert.


In genau diesem Fall wird steady_clockQueryPerformanceCounter() (siehe VC\include\chrono, für struct steady_clock suchen) mit implementiert, so dass es sehr genau und präzise sein, als dass der bevorzugten Windows-API ist für die genaue Zeitmessungen zu verwenden.

system_clock wird mit GetSystemTimePreciseAsFileTime() implementiert (siehe VC\include\chrono, für struct system_clock suchen), das "das höchstmögliche Maß an Präzision (< 1us)" auch verspricht. Leider, wie die MSDN-Seite sagt, wird diese API nur von Windows 8 unterstützt und Sie sind mit der älteren GetSystemTimeAsFileTime() mit nur ms Präzision auf Ihrem Windows 7-Rechner fest. Und das ist wahrscheinlich das Ergebnis Ihrer Messfehler.


Je nach Ihrem genauen Anwendungsfall, können Sie mit diesem auf verschiedene Weise natürlich behandeln. Ich würde in Betracht ziehen, den kleinen Fehler einfach zu ignorieren, da das Anhalten des Threads und das Warten darauf, dass der Scheduler es aufweckt, ohnehin nicht sehr genau ist.

+0

Es sieht so aus, als ob der Grund in der Tat von den Unterschieden in den Uhren kommt, die von 'sleep_for' und meiner Messmethode verwendet werden. Um zu überprüfen, dass ich die Messuhr vorübergehend auf 'system_clock' umgestellt habe, sind die Ergebnisse wie erwartet. Es ist jedoch ziemlich misstrauisch, da Sie diesen Effekt nicht lokal reproduziert haben, was mich denken lässt, dass Ihr 'sleep_for'' steady_clock' verwendet. Wenn ja, wenn es von den Betriebssystembedingungen abhängt, gibt es eine Möglichkeit, 'sleep_for'' steady_clock' zu verwenden? – dawid

+0

Dies ist intern in der CRT implementiert, nicht einmal durch "chrono" -Schnittstellen, also müssten Sie es neu aufbauen - also nein. Windows-Upgrade> = 8 würde alles lösen, oder Sie könnten nur eine kleine Menge an Dauer auf den betroffenen Plattformen hinzufügen (um die Anforderung "wartet auf> = X" immer wahr zu machen). – Yirkha

2

Während Standard sagt, dass eine Implementierung sollte ein steady_clock für die *_for Timing-Funktionen verwenden, dass nicht erforderlich ist. Und wenn ein nicht stabiler Takt verwendet wird, können Anpassungen des Taktes dazu führen, dass die Schlafzeit unterschritten wird. In diesem Fall bieten die Timing-Funktionen möglicherweise keine nützliche Funktionalität wie vom Standard angegeben.

Ihre Ergebnisse zeigen jedoch einen konsistenten kurzen Abfall, was meines Erachtens auf ein Verhalten hindeuten könnte, das nicht dem Standard entspricht.

Sie können dieses Verhalten umgehen, indem Sie die Zeit selbst mit der Uhr Ihrer Wahl messen und in einer Schleife schlafen, bis die Zielzeit verstrichen ist.

Verwandte Themen