2016-03-02 7 views
9

Diamo il seguente pezzo di codice, che semplicemente misura la durata del std::this_thread::sleep_for chiamato con 20ms: std :: :: this_thread sleep_for posti letto più breve del previsto in VS2015

#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"; 
    } 
} 

Quando condotta secondo compilato con set di strumenti V120 (VS2013 di) ottengo risultati come previsto, vale a dire:

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 

ma quando eseguito con V140 set di strumenti di VS2015, i risultati sono un po 'sorprendente e non rispettano la promessa sia da msdn e cppreference.com 01.237.837,855 miladescrizioni (che sleep_for blocca l'esecuzione del thread corrente per almeno specificato sleep_duration). Essi sono i seguenti:

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 

Come il suo possibile e come posso fare di VS2015 sleep_for a dormire almeno fino a come previsto?

saluti, Dawid

EDIT:

come richiesto quelle sono le mie impostazioni e le informazioni del sistema operativo:
OS:

  • Windows 7 Professional 64bit

  • Studios visivi: 2010 Ultimate 2013 della Comunità, 2015 Professional con Update 1

impostazioni del compilatore:

  • impostazioni predefinite per applicazione console Win32,

  • qualsiasi debug e Release configurazioni,

  • uno qualsiasi di x86 e x64 target platform archit ectures

+0

Generalmente uso 'sleep_until()' in un ciclo in caso di sveglia anticipata. Penso che il risveglio anticipato non dovrebbe accadere, ma su GCC Linux, almeno, il risveglio anticipato sembra avvenire ogni volta che il processo riceve un segnale (ovviamente non è il tuo problema qui). – Galik

+0

Non vedo gli stessi risultati localmente o ad es. su http://rextester.com/l/cpp_online_compiler_visual (utilizza anche VS2015). Prendi in considerazione l'aggiunta di ulteriori informazioni sulle esatte impostazioni del compilatore, l'architettura di destinazione, il sistema operativo host, le specifiche della macchina, ecc. – Yirkha

+0

@Yirkha: ho aggiunto ulteriori dettagli sulle mie condizioni nella descrizione. Per quanto riguarda i risultati ottenuti, sembrerà che citi piccole differenze nel mio sistema. – dawid

risposta

8

L'implementazione sleep_for() metodo in VS2015 contiene già un anello intorno alla chiamata di sistema Sleep(), in modo che qualsiasi wakeups spuri non influirà esso - vedere _Thrd_sleep() in VC\crt\src\stl\cthread.c.


la causa dei vostri problemi è più probabilmente il fatto che sleep_for() e sleep_until() che chiama dentro, stanno usando chrono::system_clock per calcolare il tempo di attesa, ma si sta misurando il periodo di utilizzo chrono::steady_clock.

Entrambi i timer possono avere la stessa precisione, ma non necessariamente la stessa precisione. Quindi può succedere che lo system_clock stia un po 'in ritardo, mentre lo steady_clock è già qualche μ avanti, e l'attesa calcolata usando system_clock è in realtà più breve di quanto richiesto.


In questo caso preciso, steady_clock è implementato utilizzando QueryPerformanceCounter() (vedi VC\include\chrono, cercare struct steady_clock), quindi sarà molto accurata e precisa, in quanto questo è l'API di Windows preferito da utilizzare per misure di tempo esatte.

system_clock è implementato utilizzando GetSystemTimePreciseAsFileTime() (vedi VC\include\chrono, cercare struct system_clock), che promette "il più alto livello possibile di precisione (< 1us)" anche. Purtroppo, come dice la pagina MSDN, questa API è supportata solo da Windows 8 in su e tu sei bloccato con il precedente GetSystemTimeAsFileTime() con precisione MS sul tuo computer Windows 7. E questo è molto probabilmente il risultato dei tuoi errori di misurazione.


A seconda del caso di utilizzo esatto, è possibile gestirlo in modi diversi, naturalmente. Considererei solo ignorando il piccolo errore, poiché sospendere il thread e attendere che lo scheduler lo riattivi non sarà comunque molto accurato.

+0

Sembra che la ragione di questo comportamento derivi dalle differenze negli orologi usati da "sleep_for" e dal mio metodo di misurazione. Per verificare che ho temporaneamente modificato il clock di misurazione su 'system_clock' ei risultati sono come previsto. Tuttavia è abbastanza sospetto dal momento che non hai riprodotto localmente questo effetto che mi fa pensare che il tuo 'sleep_for' usi' steady_clock'. Se è così, se dipende dalle condizioni del sistema operativo, c'è un modo per far sì che 'sleep_for' usi' steady_clock'? – dawid

+0

Questo è implementato internamente nel CRT, nemmeno attraverso le interfacce 'chrono', quindi dovresti ricostruirlo - quindi no. L'aggiornamento di Windows> = 8 risolverà tutto, oppure potresti aggiungere una piccola quantità di durata sulle piattaforme interessate (per rendere sempre vero il requisito "aspetta per> = X"). – Yirkha

2

Mentre norma dice che un'implementazione dovrebbe utilizzare un steady_clock per le funzioni di temporizzazione *_for, che non è necessario. E se si utilizza un orologio non costante, le regolazioni nell'orologio possono comportare una riduzione del tempo di spegnimento. In tal caso, le funzioni di temporizzazione potrebbero non fornire la funzionalità utile come indicato dallo standard.

Tuttavia, i risultati mostrano una caduta corta consistente, che a mio avviso potrebbe indicare un comportamento non conforme allo standard.

È possibile aggirare tale comportamento misurando il tempo da soli utilizzando l'orologio di propria scelta e dormendo in un ciclo fino a quando il tempo obiettivo è passato.

Problemi correlati