De drie klokken

De drie klokken

Een klok bestaat uit een startpunt en een tijdtik. C++ biedt met std::chrono::system_clock, std::chrono::steady_clock en std::chrono::high_resolution_clock drie klokken.

De klokken

Door drie verschillende klokken is er de vraag:wat zijn de verschillen?

  • std::chrono::system_clock: Is de systeembrede real-time klok (wandklok). De klok heeft de hulpfuncties to_time_t en from_time_t om tijdstippen om te zetten in datums.
  • std::chrono::steady_clock: Geeft als enige klok de garantie dat je hem niet kunt verstellen. Daarom is std::chrono::steady_clock de geprefereerde klok om te wachten op een bepaalde tijdsduur of tot een tijdstip.
  • std::chrono::high_resolution_clock: Is de klok met de hoogste nauwkeurigheid, maar het kan een synoniem zijn voor de std::chrono::system_clock of std::chrono::steady_clock van de klok.

De C++-standaard geeft geen garantie over de nauwkeurigheid, het startpunt of het geldige tijdbereik van de klokken. Typisch is het startpunt van std::chrono:system_clock 1.1.1970, het zogenaamde UNIX-tijdperk. Voor std::chrono::steady_clock, meestal de opstarttijd van uw pc.

Nauwkeurigheid en stabiliteit

Het is interessant om te weten welke klokken stabiel zijn en welke nauwkeurigheid ze bieden. Je krijgt de antwoorden van de klokken.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// clockProperties.cpp

#include <chrono>
#include <iomanip>
#include <iostream>

template <typename T>
void printRatio(){ 
 std::cout << " precision: " << T::num << "/" << T::den << " second " << std::endl;
 typedef typename std::ratio_multiply<T,std::kilo>::type MillSec;
 typedef typename std::ratio_multiply<T,std::mega>::type MicroSec;
 std::cout << std::fixed;
 std::cout << " " << static_cast<double>(MillSec::num)/MillSec::den << " milliseconds " << std::endl;
 std::cout << " " << static_cast<double>(MicroSec::num)/MicroSec::den << " microseconds " << std::endl;
}

int main(){
 
 std::cout << std::boolalpha << std::endl;
 
 std::cout << "std::chrono::system_clock: " << std::endl;
 std::cout << " is steady: " << std::chrono::system_clock::is_steady << std::endl;
 printRatio<std::chrono::system_clock::period>();
 
 std::cout << std::endl;
 
 std::cout << "std::chrono::steady_clock: " << std::endl;
 std::cout << " is steady: " << std::chrono::steady_clock::is_steady << std::endl;
 printRatio<std::chrono::steady_clock::period>();
 
 std::cout << std::endl;
 
 std::cout << "std::chrono::high_resolution_clock: " << std::endl;
 std::cout << " is steady: " << std::chrono::high_resolution_clock::is_steady << std::endl;
 printRatio<std::chrono::high_resolution_clock::period>();
 
 
 std::cout << std::endl;
 
}

Ik geef in de regels 22, 28 en 34 voor elke klok weer of deze continu is. Mijn baan in de functie printRatio (regel 7 - 15) is uitdagender. Ten eerste toon ik de nauwkeurigheid van de klokken in een breuk, ten tweede in een zwevend getal. Daarom gebruik ik de functiesjabloon std::ratio_multiply en de constanten std::kilo en std::mega om de eenheden aan te passen aan milliseconden en microseconden. U kunt de details over de berekening tijdens het compileren krijgen op cppreference.com.

De output op Linux verschilt van die op Windows. std::chrono::system_clock is veel nauwkeuriger op Linux; std::chrono::high_resultion_clock is stabiel op Windows.

Hoewel de C++-standaard het tijdperk van de klok niet specificeert, kun je het wel berekenen.

Epoche

Dankzij de hulpfunctie time_since_epoch krijg je van elk tijdstip te zien hoeveel tijd er is verstreken sinds het tijdperk.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// now.cpp

#include <chrono>
#include <iomanip>
#include <iostream>

template <typename T>
void durationSinceEpoch(T dur){
 std::cout << " Counts since epoch: " << dur.count() << std::endl;
 typedef std::chrono::duration<double, std::ratio<60>> MyMinuteTick;
 MyMinuteTick myMinute(dur);
 std::cout << std::fixed;
 std::cout << " Minutes since epoch: "<< myMinute.count() << std::endl;
 typedef std::chrono::duration<double, std::ratio<60*60*24*365>> MyYearTick;
 MyYearTick myYear(dur);
 std::cout << " Years since epoch: " << myYear.count() << std::endl;
}
 
int main(){
 
 std::cout << std::endl;
 
 std::chrono::system_clock::time_point timeNowSysClock = std::chrono::system_clock::now(); 
 std::chrono::system_clock::duration timeDurSysClock= timeNowSysClock.time_since_epoch();
 std::cout << "std::chrono::system_clock: " << std::endl;
 durationSinceEpoch(timeDurSysClock);
 
 std::cout << std::endl;
 
 auto timeNowStClock = std::chrono::steady_clock::now(); 
 auto timeDurStClock= timeNowStClock.time_since_epoch();
 std::cout << "std::chrono::steady_clock: " << std::endl;
 durationSinceEpoch(timeDurStClock);
 
 std::cout << std::endl;
 
 auto timeNowHiRes = std::chrono::high_resolution_clock::now(); 
 auto timeDurHiResClock= timeNowHiRes.time_since_epoch();
 std::cout << "std::chrono::high_resolution_clock: " << std::endl;
 durationSinceEpoch(timeDurHiResClock);
 
 std::cout << std::endl;

}

De variabelen timeDurSysClock (regel 24), timeNowStClock (regel 31) en timeNowHiResClock (Zeile 38) houden voor elke klok vast hoeveel tijd er is verstreken sinds het begin van de klok. Wanneer ik geen automatische typeaftrek gebruik met auto, zijn expliciete typen van het tijdstip en de tijdsduur extreem uitgebreid om te schrijven. In de functie durationSinceEpoch (regels 7 - 17) laat ik de tijdsduur in verschillende resoluties zien. Eerst geef ik het aantal tijdtikken weer (regel 9), dan het aantal minuten (regel 13) en aan het einde van de jaren (regel 16) sinds het tijdperk, allemaal afhankelijk van de gebruikte klok. Ik negeer schrikkeljaren om redenen van eenvoud, en mijn jaar heeft 365 dagen.

De resultaten zijn verschillend op Linux en Windows.

Om de juiste conclusie te trekken, moet ik vermelden dat mijn Linux-pc ongeveer 5 uur (305 minuten) draait en mijn Windows-pc meer dan 6 uur (391 minuten).

std::chrono::system_clock en std::chrono::high_resolution_clock hebben op Linux het UNIX-tijdperk als uitgangspunt. Het startpunt van std::chrono::steady_clock is de opstarttijd van mijn pc. Het verschil tussen Linux en Windows is std::high_resolution_clock. Op Linux wordt de std::chrono::system_clock intern gebruikt; op Windows wordt de std::chrono::steady_clock intern gebruikt.

Wat nu?

Dat is niet het einde van het verhaal over de nieuwe tijdbibliotheek. Met het tijdstip en de tijdsduur van het onderdeel kunt u een draad plaatsen voor een absolute of relatieve slaaptijd. De details volgen in het volgende bericht.