Die Boost C++ Bibliotheken

Kapitel 37. Boost.Chrono

Die Bibliothek Boost.Chrono bietet verschiedene Uhren an. So können Sie zum Beispiel die aktuelle Uhrzeit erhalten, so wie sie üblicherweise auf dem Desktop Ihres Computers angezeigt wird. Sie können jedoch auch Uhren verwenden, die es Ihnen erlauben zu messen, wie viel Zeit in einem Prozess verstrichen ist.

Boost.Chrono ist teilweise in den Standard C++11 eingegangen. So können Sie, wenn Ihre Entwicklungsumgebung C++11 unterstützt, auf einige Uhren über die Headerdatei chrono zugreifen. C++11 bietet aber zum Beispiel keine Uhren an, um die CPU-Zeit zu messen. Boost.Chrono unterstützt außerdem eine benutzerdefinierte Formatierung zur Ausgabe von Zeiten.

Sie können auf alle Uhren aus Boost.Chrono über die Headerdatei boost/chrono.hpp zugreifen. Einzige Ausnahme ist die benutzerdefinierte Formatierung. In diesem Fall müssen Sie zusätzlich die Headerdatei boost/chrono_io.hpp einbinden.

Beispiel 37.1. Alle Uhren von Boost.Chrono
#include <boost/chrono.hpp>
#include <iostream>

using namespace boost::chrono;

int main()
{
  std::cout << system_clock::now() << '\n';
#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
  std::cout << steady_clock::now() << '\n';
#endif
  std::cout << high_resolution_clock::now() << '\n';

#ifdef BOOST_CHRONO_HAS_PROCESS_CLOCKS
  std::cout << process_real_cpu_clock::now() << '\n';
  std::cout << process_user_cpu_clock::now() << '\n';
  std::cout << process_system_cpu_clock::now() << '\n';
  std::cout << process_cpu_clock::now() << '\n';
#endif

#ifdef BOOST_CHRONO_HAS_THREAD_CLOCK
  std::cout << thread_clock::now() << '\n';
#endif
}

Beispiel 37.1 stellt alle Uhren vor, die Boost.Chrono anbietet. Allen Uhren ist gemeinsam, dass sie eine Methode now() definieren, die einen Zeitpunkt zurückgibt. Alle Zeitpunkte werden abhängig von der Uhr relativ zu einem universell gültigen Zeitpunkt gemessen. Man spricht dabei von einer Epoche. Eine oft verwendete Epoche ist der 1. Januar 1970. Wenn Sie Beispiel 37.1 ausführen, wird für alle Zeitpunkte die Epoche mit ausgegeben.

Boost.Chrono kennt folgende Uhren:

Beachten Sie, dass alle von Boost.Chrono angebotenen Uhren auf Betriebssystemfunktionen angewiesen sind. Es hängt demnach vom Betriebssystem ab, wie genau und verlässlich die zurückgegebenen Zeiten sind.

Beispiel 37.2. Zeiträume von Boost.Chrono
#include <boost/chrono.hpp>
#include <iostream>

using namespace boost::chrono;

int main()
{
  process_real_cpu_clock::time_point p = process_real_cpu_clock::now();
  std::cout << p << '\n';
  std::cout << p - nanoseconds{1} << '\n';
  std::cout << p + milliseconds{1} << '\n';
  std::cout << p + seconds{1} << '\n';
  std::cout << p + minutes{1} << '\n';
  std::cout << p + hours{1} << '\n';
}

Der Aufruf von now() gibt für alle Uhren ein Objekt vom Typ boost::chrono::time_point zurück. boost::chrono::time_point ist eng mit einer Uhr verzahnt, da ein Zeitpunkt nur abhängig von einem absoluten Referenzpunkt gemessen werden kann – und dieser ist in Boost.Chrono per Uhr definiert. boost::chrono::time_point ist entsprechend ein Template, das unter anderem eine Uhrenklasse als Parameter erwartet. Uhrenklassen bietet ihrerseits eine Typedefinition für ihren spezialisierten boost::chrono::time_point an. process_real_cpu_clock::time_point ist die entsprechende Typdefinition für die Uhrenklasse process_real_cpu_clock.

Neben boost::chrono::time_point bietet Boost.Chrono eine Klasse boost::chrono::duration an, die Zeiträume beschreibt. Da es sich bei boost::chrono::duration ebenfalls um ein Template handelt, bietet Boost.Chrono mit boost::chrono::nanoseconds, boost::chrono::milliseconds, boost::chrono::microseconds, boost::chrono::seconds, boost::chrono::minutes und boost::chrono::hours sechs einfach zu verwendende Klassen an.

Boost.Chrono überlädt viele Operatoren, um mit Zeitpunkten und -räumen arbeiten zu können. So werden im Beispiel 37.2 Zeiträume von p subtrahiert oder zu p hinzuaddiert, um neue Zeitpunkte zu erhalten. Diese werden direkt auf die Standardausgabe ausgegeben.

Wenn Sie Beispiel 37.2 ausführen, stellen Sie fest, dass die Ausgabe aller Zeitpunkte mit der Einheit Nanosekunden erfolgt. Beim Arbeiten mit Zeitpunkten und -räumen verwendet Boost.Chrono automatisch die kleinste Einheit, um sicherzustellen, dass Ergebnisse exakt sind. Möchten Sie einen Zeitpunkt mit einer anderen Einheit verwenden, müssen Sie ihn casten.

Beispiel 37.3. Zeitpunkte casten mit boost::chrono::time_point_cast()
#include <boost/chrono.hpp>
#include <iostream>

using namespace boost::chrono;

int main()
{
  process_real_cpu_clock::time_point p = process_real_cpu_clock::now();
  std::cout << p << '\n';
  std::cout << time_point_cast<minutes>(p) << '\n';
}

Boost.Chrono stellt mit boost::chrono::time_point_cast() eine Funktion zur Verfügung, die wie ein Cast-Operator verwendet wird. So können Sie wie im Beispiel 37.3 einen Zeitpunkt, der auf der Einheit Nanosekunden basiert, in einen Zeitpunkt umwandeln, der auf Minuten basiert. Da nicht jeder beliebige Zeitpunkt in Nanosekunden gemessen als Zeitpunkt in Minuten dargestellt werden kann, muss boost::chrono::time_point_cast() verwendet werden. Die entgegengesetzte Umwandlung von Minuten in Nanosekunden ist implizit möglich – Sie müssen in diesem Fall nicht auf boost::chrono::time_point_cast() zugreifen.

Boost.Chrono stellt auch für Zeiträume einen Cast-Operator zur Verfügung, der aus dem gleichen Grund wie boost::chrono::time_point_cast() verwendet werden muss.

Beispiel 37.4. Zeiträume casten mit boost::chrono::duration_cast()
#include <boost/chrono.hpp>
#include <iostream>

using namespace boost::chrono;

int main()
{
  minutes m{1};
  seconds s{35};

  std::cout << m + s << '\n';
  std::cout << duration_cast<minutes>(m + s) << '\n';
}

Im Beispiel 37.4 kommt die Funktion boost::chrono::duration_cast() zum Einsatz, um einen Zeitraum in Sekunden in einen Zeitraum in Minuten umzuwandeln. Das Beispielprogramm gibt entsprechend 1 minute aus.

Beispiel 37.5. Zeitpunkte runden
#include <boost/chrono.hpp>
#include <iostream>

using namespace boost::chrono;

int main()
{
  std::cout << floor<minutes>(minutes{1} + seconds{45}) << '\n';
  std::cout << round<minutes>(minutes{1} + seconds{15}) << '\n';
  std::cout << ceil<minutes>(minutes{1} + seconds{15}) << '\n';
}

Boost.Chrono bietet neben boost::chrono::duration_cast() Funktionen an, um Zeiträume beim Casten zu runden. boost::chrono::round() rundet automatisch auf oder ab. boost::chrono::floor() rundet immer ab, boost::chrono::ceil() immer auf. boost::chrono::floor() verwendet boost::chrono::duration_cast() – es gibt keinen Unterschied zwischen diesen beiden Funktionen.

Beispiel 37.5 gibt 1 minute, 1 minute und 2 minutes auf die Standardausgabe aus.

Beispiel 37.6. Stream-Manipulatoren für benutzerdefinierte Ausgabe
#define BOOST_CHRONO_VERSION 2
#include <boost/chrono.hpp>
#include <boost/chrono/chrono_io.hpp>
#include <iostream>

using namespace boost::chrono;

int main()
{
  std::cout << symbol_format << minutes{10} << '\n';

  std::cout << time_fmt(boost::chrono::timezone::local, "%H:%M:%S") <<
    system_clock::now() << '\n';
}

Boost.Chrono bietet verschiedene Stream-Manipulatoren, um die Ausgabe von Zeiträumen und -punkten zu formatieren. So kann der Manipulator boost::chrono::symbol_format() verwendet werden, um die Zeiteinheit mit einem Symbol anstatt mit einem ausgeschriebenen Namen anzugeben. Im Beispiel 37.6 wird entsprechend 10 min ausgegeben.

Der Manipulator boost::chrono::time_fmt() kann verwendet werden, um sowohl eine Zeitzone als auch eine Formatierung festzulegen. Die Zeitzone muss entweder boost::chrono::timezone::local oder boost::chrono::timezone::utc sein. Die Formatierung ist ein String, in dem mit verschiedenen Kürzeln auf die einzelnen Bestandteile eines Zeitpunkts Bezug genommen wird. So wird im Beispiel 37.6 zum Beispiel 15:46:44 ausgegeben.

Neben Stream-Manipulatoren bietet Boost.Chrono auch zahlreiche Facets. So können Sie mit ihrer Hilfe zum Beispiel Zeiteinheiten in einer anderen Sprache ausgeben.

Anmerkung

Beachten Sie, dass die Input/Output-Funktionen seit Boost 1.52.0 in zwei Versionen vorliegen. Seit Boost 1.55.0 wird standardmäßig die neue Version verwendet. Verwenden Sie eine ältere Version als 1.55.0, müssen Sie wie im Beispiel geschehen das Makro BOOST_CHRONO_VERSION definieren und auf 2 setzen.