Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

User's Guide

Boost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 7. Boost.Chrono 2.0.5

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext
Getting Boost.Chrono

Boost.Chrono находится в последнем выпуске Boost в папке /boost/chrono. Документация, тесты и примеры папки на boost/libs/chrono/.

Простой способ - декомпрессировать (или проверить с SVN) файлы в вашем каталоге BOOST_ROOT.

Building Boost.Chrono

Boost.Chrono может быть сконфигурирована как библиотека только для заголовка, определяющая BOOST_CHRONO_HEADER_ONLY. Как бы то ни было. Chrono зависит от библиотеки только для заголовка Boost. Система, так что вам нужно будет связаться с бустерной_системой.

Подъем. Система имеет недокументированную особенность (использование макро BOOST_ERROR_CODE_HEADER_ONLY), чтобы сделать его только заголовок.

Если BOOST_CHRONO_HEADER_ONLY не определено, вам нужно скомпилировать его и построить библиотеку перед использованием, например, используя:

bjam libs/chrono/build
Requirements

В частности, Boost.Chrono зависит от:

Boost.Config

для конфигурационных целей...

Boost.Exception

для броска_исключения, ...

Boost.Integer

...

Boost.MPL

для MPL Assert и bool, логично...

Boost.Operators

для операторов, ...

Boost.Ratio

для соотношения, милли, микро, ...

Boost.System

for error_code, ...

Boost.TypeTraits

для is_base, is_convertible, common_type, ...

Boost.Utility/EnableIf

for enable_if, ...

Building an Executable that Uses Boost.Chrono

Помимо связи с библиотекой Boost.Chrono необходимо также связать с библиотекой Boost.System. Если Boost.System настроена на определение BOOST_ERROR_CODE_HEADER_ONLY Вам не нужно будет связываться с ним, поскольку зависимая часть является головной уборкой только тогда.

Exception safety

Все функции в библиотеке являются нейтральными для исключения и обеспечивают надежную гарантию безопасности исключений до тех пор, пока ее обеспечивают основные параметры.

Thread safety

Все функции в библиотеке небезопасны, за исключением случаев, когда они четко указаны.

Как буст. Chrono не использует смутные глобальные переменные, анализ резьбы-безопасности ограничивается доступом к каждой переменной экземпляра. Не безопасно использовать функцию, которая изменяет доступ к переменной пользователя, если другой может читать или писать ее.

Tested compilers

Реализация в конечном итоге будет работать с большинством компиляторов C++03. В настоящее время я использую для тестирования на:

Windows

  • MSVC 10.0

MinGW с

  • GCC 4.5.0
  • GCC 4.5.0 -std=c++0x
  • GCC 4.5.2
  • GCC 4.5.2 -std=c++0x
  • GCC 4.6.0
  • GCC 4.6.0 -std=c++0x
  • GCC 4.8.0
  • GCC 4.8.0 -std=c++0x

Ubuntu с * GCC 4.4.6 * GCC 4.4.6 -std=c++0x * GCC 4.5.4 * GCC 4.5.4 -std=c++0x * GCC 4.6.1 * GCC 4.6.1 -std=c++0x * Intel 12.1.3 * Intel 12.1.3 -std=c++0x

OsX

  • GCC 4.1.2
  • GCC 4.6.2
  • GCC 4.6.2 -std=c++0x
  • GCC 4.7.0
  • GCC 4.7.0 -std=c++0x
  • GCC 4.7.1
  • GCC 4.7.1 -std=c++0x
  • GCC 4.7.2
  • GCC 4.7.2 -std=c++0x
  • GCC 4.8.0
  • GCC 4.8.0 -std=c++0x
  • GCC 4.8.1
  • GCC 4.8.1 -std=c++0x
  • кланг 3.1
  • кланг 3.1 -std=c++0x -stdlib=libc++
  • кланг 3,2
  • clang 3.2 -std=c++11 -stdlib=libc++

Обязательный код тестируется гораздо больше компиляторов. Есть два компилятора (VACPP и Borland), которые не предоставляют необходимые функции. Другие, как Intel и Sun, имеют некоторые проблемы с i/o. В то время как все компилируется и связывается правильно, есть некоторые проблемы времени работы, которые я еще не кэшировал. Подробности см. в тестах на регрессию.

[Note] Note

Пожалуйста, сообщите нам, как это работает на других платформах/компиляторах.

[Note] Note

Пожалуйста, присылайте любые вопросы, комментарии и отчеты об ошибках, чтобы увеличить списки .

Производство является сердцем этой библиотеки. Интерфейс, который пользователь будет видеть в повседневном использовании, почти идентичн интерфейсу Boost.DateTime время duration, написанному Джеффом Гарландом, как в синтаксисе, так и в поведении. Это была очень популярная библиотека импульса в течение 7 лет. Существует огромная положительная история с этим интерфейсом.

Библиотека состоит из шести единиц времени Производство:

Эти единицы были выбраны в качестве подмножества библиотеки, потому что они являются наиболее распространенными единицами, используемыми при сне, ожидая переменной состояния или ожидая получения блокировки наmut. Каждая из этих единиц - не что иное, как тонкая обертка вокруг подписанного интегрального графа. То есть, когда вы строите минуты(3), все, что происходит, это 3, хранится внутри минут. Когда вы строите микросекунды(3), все, что происходит, это 3 хранится внутри микросекунды.

Единственный контекст, в котором эти различные типы различаются, заключается в преобразовании друг в друга. В настоящее время константы для преобразования исходной единицы в целевую единицу используются для преобразования исходной единицы. Разрешены только конверсии из гребцовых единиц в штрафные единицы (в Boost). Это ограничение гарантирует, что все конверсии всегда точны. То есть микросекунды всегда могут представлять любую ценность минуты.

В Boost.DateTime эти единицы объединены посредством наследования. Boost.Chrono вместо этого объединяет эти единицы через шаблон класса дукция. То есть, в Boost.Chrono все шесть вышеперечисленных единиц - это не что иное, как типопады для различных мгновенных сообщений дукция. Это изменение от Boost. DateTime имеет далеко идущие положительные последствия, не меняя синтаксис повседневного использования вообще.

Самое непосредственное положительное влияние заключается в том, что библиотека может сразу генерировать любой блок, с любой точностью, в которой он нуждается. Иногда это необходимо при проведении сравнений или арифметики между дукция различной точности, предполагая, что нужно точное сравнение и арифметика.

Вторичное преимущество заключается в том, что, публикуя шаблон класса дукция интерфейс, пользовательский код может очень легко создать дурация с любой точностью, которую они хотят. Для уточнения точности используется утилита ratio, так что до тех пор, пока точность может быть выражена рациональной константой в отношении секунд, эта система может точно представлять ее (одна треть секунды не является проблемой, и ни одна треть femto вторая). Вся эта утилита и гибкость обходятся без затрат, просто используя беспосадочную нагрузку ratio.

В Boost.DateTime часы не имеют такого же представления, как nanoseconds. Первый обычно представлен с long, тогда как для последнего требуется longlong. Причина этого - просто диапазон. Вам не нужно много часов, чтобы покрыть чрезвычайно большой промежуток времени. Но это не относится к наносекундам. Возможность уменьшить размер накладных расходов на некоторые единицы, когда это возможно, может быть значительным преимуществом производительности.

Boost.Chrono продолжается и обобщает эту философию. Не только можно указать точность дутерации, можно также указать ее представление. Это может быть любой интегральный тип или даже плавающий тип. Или это может быть определяемый пользователем тип, который эмулирует арифметический тип. Шесть предопределенных единиц используют подписанные интегральные типы в качестве их представления. И все они имеют минимальный диапазон ± 292 года. наносекунды нуждаются в 64 битах для покрытия этого диапазона. часы нуждаются только в 23 битах для покрытия этого диапазона.

A duration имеет представление и период клеща (тренировки).

template <class Rep, class Period = ratio<1> > class duration;

Представление - это просто любой арифметический тип или эмуляция такого типа. Представления хранят количество клещей. Этот счет является единственным членом данных, хранящимся в производство. Если представление является плавающей точкой, оно может хранить фракции клеща до точности представления. Период клеща представлен ratio и закодирован в тип duration, а не хранится. Часовой период оказывает влияние только на поведение дуляция, когда происходит преобразование между различными дукция. Часовой период полностью игнорируется при простом выполнении арифметики среди таких как durations.

Пример:

typedef boost::chrono::duration<long, boost::ratio<60> > minutes;
minutes m1(3);                 // m1 stores 3
minutes m2(2);                 // m2 stores 2
minutes m3 = m1 + m2;          // m3 stores 5
typedef boost::chrono::duration<long long, boost::micro> microseconds;
microseconds us1(3);           // us1 stores 3
microseconds us2(2);           // us2 stores 2
microseconds us3 = us1 + us2;  // us3 stores 5
microseconds us4 = m3 + us3;   // us4 stores 300000005

В последней строке кода выше есть неявное преобразование от минут до микросекунд, что приводит к относительно большому количеству микросекунд.

Если вам нужно получить доступ к количеству клещей в пределах дукция, есть член count(), который просто возвращает сохраненный тик.

long long tc = us4.count();    // tc is 300000005

Эти производство имеют очень простое, очень предсказуемое и очень наблюдаемое поведение. В конце концов, это на самом деле не что иное, как проверенный временем интерфейс времени повышения Джеффа дукция библиотека (объединенная с шаблонами вместо наследования).

minutes m4 = m3 + us3;

Он не будет компилироваться! Обоснование состоит в том, что имплицитная ошибка усечения не должна допускаться. Если бы это было компилировано, то m4 занимал бы 5, то же значение, что и m3. Значение, связанное с us3, было фактически проигнорировано. Это похоже на проблему присвоения двойника int: дробная часть молча отбрасывается.

Существует объект duration_cast, чтобы явно спросить об этом поведении:

minutes m4 = boost::chrono::duration_cast<minutes>(m3 + us3);  // m4.count() == 5

В целом, можно выполнить дурацию арифметика по желанию. Если duration_cast не используется, и он компилируется, арифметика точна. Если кто-то хочет переопределить это точное арифметическое поведение, duration_cast может быть использован для четкого указания этого желания. duration_cast имеет ту же эффективность, что и неявная конверсия, и даже будет точно так же часто, как может.

Вы можете использовать duration_cast<> для преобразования duration в любые единицы, которые вы хотите. Этот объект будет закругляться (выключаться), если точное преобразование невозможно. Например:

boost::chrono::nanoseconds start;
boost::chrono::nanoseconds end;
typedef boost::chrono::milliseconds ms;
ms d = boost::chrono::duration_cast<ms>(end - start);
// d now holds the number of milliseconds from start to end.
std::cout << ms.count() << "ms\n";

Мы можем конвертировать в наносекунды, или некоторую интегральную продолжительность, которая наносекунды всегда будет точно конвертировать в, затем duration_cast> не требуется:

typedef boost::chrono::nanoseconds ns;
ns d = end - start;
std::cout << ns.count() << "ns\n";

Если вам нужны секунды с представлением с плавающей точкой, вы также можете устранить duration_cast<>:

typedef boost::chrono::duration<double> sec;  // seconds, stored with a double
sec d = end - start;
std::cout << sec.count() << "s\n";

Если вы не уверены, нужно ли вам duration_cast< или нет, не стесняйтесь попробовать это без. Если конверсия точна, или если пункт назначения имеет представление с плавающей точкой, он будет компилироваться: иначе он не будет компилироваться.

Если вам нужно использовать duration_cast<, но хотите округлить, а не вниз, когда преобразование неактуально, вот небольшая функция помощника для этого. На самом деле это хороший стартовый проект для понимания Боост.Chrono:

template <class ToDuration, class Rep, class Period>
ToDuration
round_up(boost::chrono::duration<Rep, Period> d)
{
    // first round down
    ToDuration result = boost::chrono::duration_cast<ToDuration>(d);
    if (result < d)  // comparisons are *always* exact
       ++result;     // increment by one tick period
    return result;
}
typedef boost::chrono::milliseconds ms;
ms d = round_up<ms>(end - start);
// d now holds the number of milliseconds from start to end, rounded up.
std::cout << ms.count() << "ms\n";

Boost.Chrono предоставляет несколько простых функций округления для работы с продолжительностью.

// round down
template <class To, class Rep, class Period>
To
floor(const duration<Rep, Period>& d)
{
    return duration_cast<To>(d);
}
// round to nearest, to even on tie
template <class To, class Rep, class Period>
To
round(const duration<Rep, Period>& d)
{
    To t0 = duration_cast<To>(d);
    To t1 = t0;
    ++t1;
    BOOST_AUTO(diff0, d - t0);
    BOOST_AUTO(diff1, t1 - d);
    if (diff0 == diff1)
    {
        if (t0.count() & 1)
            return t1;
        return t0;
    }
    else if (diff0 < diff1)
        return t0;
    return t1;
}
// round up
template <class To, class Rep, class Period>
To
ceil(const duration<Rep, Period>& d)
{
    To t = duration_cast<To>(d);
    if (t < d)
        ++t;
    return t;
}

Красота библиотеки хроно - это легкость и точность, с которой такие конверсии могут быть сделаны. Например, для преобразования из милисекунды (1/100 секунды) в 13>/3034> секунды необходимо умножить миллисекунды на 0.03. Общеизвестно, что вы не можете точно представлять 0.03 в компьютере. Тем не менее раунд будет точно (без ошибки округления) обнаруживать связь и круг даже когда это происходит. Различия diff0 и diff1 не приблизительны, но точные различия, даже когда d имеет единицы миллисекунды и To является 1/34> секунды. Единица diff0 и diff1 - 1/300 секунды, которая как миллисекунда, так и 1/30 второй точно конвертируется в (без ошибки усечения).

Точно так же сравнение t < d в ceil является точным, даже если нет точного преобразования между t и d. Пример использования функций округления

#include <iostream>
#include <boost/chrono/chrono_io.hpp>
#include <boost/chrono/floor.hpp>
#include <boost/chrono/round.hpp>
#include <boost/chrono/ceil.hpp>
int main()
{
    using namespace boost::chrono;
    milliseconds ms(2500);
    std::cout << floor<seconds>(ms) << '\n';
    std::cout << round<seconds>(ms) << '\n';
    std::cout << ceil<seconds>(ms) << '\n';
    ms = milliseconds(2516);
    typedef duration<long, boost::ratio<1, 30> > frame_rate;
    std::cout << floor<frame_rate>(ms) << '\n';
    std::cout << round<frame_rate>(ms) << '\n';
    std::cout << ceil<frame_rate>(ms) << '\n';
    return 0;
}

Выход этой программы должен быть

2 seconds
2 seconds
3 seconds
75 [1/30]seconds
75 [1/30]seconds
76 [1/30]seconds

Я не хочу иметь дело с написанием duration_cast по всему месту. Я доволен точностью моего представления с плавающей точкой.

Не проблема. Когда пункт назначения конверсии имеет представление с плавающей точкой, все конверсии могут происходить косвенно.

typedef boost::chrono::duration<double, ratio<60> > dminutes;
dminutes dm4 = m3 + us3;  // dm4.count() == 5.000000083333333

Если вы писали эти конверсии вручную, вы не могли сделать его более эффективным. Использование ratio гарантирует, что все константы преобразования будут максимально упрощены при компиляции. Это обычно приводит к числительу или знаменательу коэффициента преобразования, упрощающего до 1, и затем игнорируется при преобразовании значений времени работы клеща.

Существует несколько вариантов, открытых для пользователя:

void f(boost::chrono::duration<double> d)  // accept floating-point seconds
{
    // d.count() == 3.e-6 when passed boost::chrono::microseconds(3)
}
f(boost::chrono::microseconds(3));
void f(boost::chrono::nanoseconds d)
{
    // d.count() == 3000 when passed boost::chrono::microseconds(3)
}
f(boost::chrono::microseconds(3));

В этом дизайне, если клиент хочет пройти в плавающей точке дукция, или дукция тонкой точности, чем наносекунды, то клиент несет ответственность за выбор собственного режима округления в преобразовании в наносекунды.

boost::chrono::duration<double> s(1./3);  // 1/3 of a second
f(boost::chrono::duration_cast<boost::chrono::nanoseconds>(s));  // round towards zero in conversion to nanoseconds

В приведенном выше примере клиент f выбрал «круг к нулю» как желаемый режим округления к наносекундам. Если клиент имеет дурацию, которая не будет точно конвертироваться в наносекунды, и не выберет, как будет происходить преобразование, компилятор откажет в вызове:

f(s);  // does not compile
  • Если автор функции хочет принять любую функцию производство, но хочет работать с интегральными представлениями и хочет контролировать режим округления внутри, то он может шаблон функции:
template <class Rep, class Period>
void f(boost::chrono::duration<Rep, Period> d)
{
    // convert d to nanoseconds, rounding up if it is not an exact conversion
    boost::chrono::nanoseconds ns = boost::chrono::duration_cast<boost::chrono::nanoseconds>(d);
    if (ns < d)
        ++ns;
    // ns.count() == 333333334 when passed 1/3 of a floating-point second
}
  f(boost::chrono::duration<double>(1./3));
  • Если автор в примере не хочет принимать плавающие точки на основе дукция, он может обеспечить такое поведение:
template <class Period>
void f(boost::chrono::duration<long long, Period> d)
{
    // convert d to nanoseconds, rounding up if it is not an exact conversion
    boost::chrono::nanoseconds ns = boost::chrono::duration_cast<nanoseconds>(d);
    if (ns < d)
        ++ns;
    // ns.count() == 333333334 when passed 333333333333 picoseconds
}
// About 1/3 of a second worth of picoseconds
f(boost::chrono::duration<long long, boost::pico>(333333333333));

Клиенты с плавающей точкой дуляция, которые хотят использовать f, теперь должны конвертировать в интеграл дурация, прежде чем передавать результат на f.

Короче говоря, автор f имеет довольно много гибкости и контроля в интерфейсе, который он хочет предоставить своим клиентам, и простые варианты для манипулирования, что duration внутренние для его функции.

Нет. Независимо от того, какой вариант автор f выбирает выше, следующий клиентский код не будет компилироваться:

f(3);  // Will not compile, 3 is not implicitly convertible to any __duration

Это зависит от представительства. Типдед по умолчанию использует представление, которое не обрабатывает переливы. Пользователь может определить свое собственное представление, которое управляет переполнением, как того требует его приложение.

В то время как duration имеют только точность и представление, чтобы заботиться о себе, часы и time_point тесно связаны и относятся друг к другу. Поскольку часы проще объяснить, мы сделаем это сначала без полного объяснения Time_point. После введения часов будет легче заполнить то, что такое Time_point.

Часы - это понятие, которое объединяет 3 вещи:

  1. Конкретный дукция тип.
  2. Конкретный time_point тип.
  3. Функция, называемая сейчас (), которая возвращает бетон Time_point.

Стандарт определяет три общесистемных часа, которые связаны с компьютерным временем.

  • система_час представляет собой общесистемные часы реального времени, которые могут быть синхронизированы с внешними часами.
  • устойчивый_час не может быть изменен явно и время с начальной эпохи увеличивается устойчивым образом.
  • хай_разрешение_час намерены использовать общесистемные часы, предоставляемые платформой с самым высоким разрешением.

Boost.Chrono предоставляет их при поддержке базовой платформы. Данная платформа может не иметь возможности поставлять все три из этих часов.

Библиотека добавляет несколько часов, которые специфичны для процесса или нити, то есть часы на процесс или на каждую нить.

Пользователь также может легко создавать больше часов.

Учитывая часы под названием Clock, он будет иметь:

class Clock {
public:
    typedef an arithmetic-like type        rep;
    typedef an instantiation of ratio      period;
    typedef boost::chrono::duration<rep, period> duration;
    typedef boost::chrono::time_point<Clock>     time_point;
    static constexpr bool is_steady =      true or false;
    static time_point now();
};

Можно получить текущее время от Clock с:

Clock::time_point t1 = Clock::now();

И можно получить время дурация между двумя Time_point, связанными с часами:

Clock::duration d = Clock::now() - t1;

И можно указать прошлое или будущее time_point с:

Clock::time_point t2 = Clock::now() + d;

Обратите внимание, что даже если определенные часы устаревают, следующие часы в строке будут иметь тот же API. Нет никакой новой кривой обучения. Единственными изменениями исходного кода будет просто изменение типа часов. Те же Производство и Time_point рамки продолжают работать по мере появления новых часов. И несколько часов безопасно и легко обрабатываются в рамках одной и той же программы.

time_point представляет собой точку во времени, в отличие от duration времени. Другой способ сказать то же самое, что time_point представляет собой эпоху плюс или минус дуция. Примеры time_point включают:

  • через 3 минуты после загрузки компьютера.
  • 19 января 2038 г
  • 20 миллисекунд после того, как я начал этот таймер.

В каждом из приведенных выше примеров подразумевается другая эпоха. Иногда эпоха имеет смысл в течение нескольких тысячелетий. В других случаях смысл эпохи теряется через некоторое время (например, начало таймера или когда компьютер загружается). Однако, если два time_point известны, чтобы разделить одну и ту же эпоху, они могут быть вычтены, уступая действительный duration, даже если определение эпохи больше не имеет значения.

В Boost.Chrono эпоха является чисто абстрактной и неопределенной концепцией. Нет типа, представляющего эпоху. Это просто идея, которая относится (или нет) Time_point к часам, и в случае, если они имеют часы, time_point друг к другу. time_point, связанные с различными часами, обычно не совместимы, если не известно взаимосвязь между эпохами, связанными с каждым часами.

A time_point имеет часы и duration.

template <class Clock, class Duration = typename Clock::duration> class time_point;

Часы time_point не хранятся. Он просто встроен в тип time_point и служит двум целям:

  1. Поскольку time_point, происходящие из разных часов, имеют разные типы, компилятор может быть проинструктирован потерпеть неудачу, если несовместимые time_point используются неуместными способами.
  2. Учитывая time_point, часто нужно сравнить это time_point на "сейчас". Это очень просто, если time_point знает, какие часы он определяется в отношении.

A time_point duration хранится как единственный член данных time_point. Таким образом, time_point и их соответствующий duration имеют точно такой же план. Но они имеют совершенно разные значения. Например, одно - сказать, что я хочу спать 3 минуты. Это совершенно другая вещь, чтобы сказать, что я хочу спать до 3 минут после того, как я начал этот таймер (если только вы не начали этот таймер сейчас). Оба значения (и варианты сна) имеют большую практическую ценность в случаях общего использования для сна, ожидания на переменной состояния и ожидания блокировкиmutа. Эти же понятия и инструменты найдены (например) в Ada.

Пример таймера:

void f()
{
    boost::chrono::steady_clock::time_point start = boost::chrono::steady_clock::now();
    g();
    h();
    duration<double> sec = boost::chrono::steady_clock::now() - start;
    cout << "f() took " << sec.count() << " seconds\n";
}

Обратите внимание, что если использовать дурацию между двумя часами Time_point таким образом, что точность дурация вопросы, это хорошая практика, чтобы преобразовать часы дурация>>> к известному дурация. Это изолирует код от будущих изменений, которые могут быть сделаны до точности часов в будущем. Например, устойчивый_час может быть легко основан на скорости часов кпу. Когда вы переходите на более быструю машину, вы не хотите, чтобы ваш код, который предполагал определенный период галочки этих часов, начал испытывать сбои в рабочем времени, потому что ваш тайм-код молча изменил смысл.

Пример задержки:

// delay for at least 500 nanoseconds:
auto go = boost::chrono::steady_clock::now() + boost::chrono::nanoseconds(500);
while (boost::chrono::steady_clock::now() < go)
    ;

Вышеупомянутый код задержится как можно ближе к половине микросекунды, независимо от точности устойчивый_час. Чем точнее устойчивый_час становится, тем точнее будет задержка до 500 наносекунд.

система_час полезна, когда вам нужно соотнести время с известной эпохой, чтобы вы могли преобразовать его в календарное время. Обратите внимание на конкретные функции в классе system_hour.

устойчивый_час полезен, когда нужно ждать определенного количества времени. устойчивый_час время не может быть сброшено. Как и другие постоянные часы, он обычно основан на процессорном клеще.

Вот решение для голосования, но оно, вероятно, будет слишком неэффективным:

boost::chrono::steady_clock::time_point start= chrono::steady_clock::now();
boost::chrono::steady_clock::duration delay= chrono::seconds(5);
while (boost::chrono::steady_clock::now() - start <= delay) {}

При наличии хай_разрешение_час, как правило, дороже, чем другие общесистемные часы, поэтому они используются только тогда, когда требуется разрешение.

Процессные и резьбовые часы обычно используются для измерения времени, затраченного на блоки кода, в качестве основного временного профилирования различных блоков кода (Boost.Chrono.Stopwatch является четким примером этого использования).

Вы можете использовать thread_hour всякий раз, когда вы хотите измерить время, проведенное текущей нитью. Например:

boost::chrono::thread_clock::time_point start=boost::chrono::thread_clock::now();
// ... do something ...
typedef boost::chrono::milliseconds ms;
ms d = boost::chrono::thread_clock::now() - start;
// d now holds the number of milliseconds from start to end.
std::cout << ms.count() << "ms\n";

Если вам нужны секунды с представлением с плавающей точкой, вы можете сделать:

typedef boost::chrono::duration<double> sec;  // seconds, stored with a double.
sec d = end - start;
std::cout << sec.count() << "s\n";

Любой Производство может передаваться на basic_ostream. Значение времени выполнения производство отформатировано в соответствии с правилами и параметрами текущего формата для производство::rep get_duration_style и длительности punct facet.

формат либо

<value> <unit>

или

<unit> <value>
[Warning] Warning

Нужно изменить За этим следует одно пространство, а затем и название единицы компиляции duration. Это имя единицы построено на строке, возвращенной из ratio_string<, и данных, используемых для построения duration_punct, которые были вставлены в локальную часть потока. Если duration_punct не был вставлен в локальную часть потока, в локальную часть потока будет добавлен по умолчанию построенный duration_punct.

Производство наименования единиц приходят в двух вариантах: длинный (префикс) и короткий (символ). По умолчанию построенный duration_punct предоставляет имена в формате long(prefix). Эти имена являются английскими описаниями. Другие языки поддерживаются построением duration_punct с надлежащими написанием для «часов», «минут» и «секунд», а также их сокращения (для короткого формата). Короткий или длинный формат может быть легко выбран путем потоковой передачи duration_short() или duration_long() manipulator соответственно или с использованием параметризованного манипулятора duration_fmt(duration_styleprefix.

Пример:

#include <iostream>
#include <boost/chrono/chrono_io.hpp>
int main()
{
    using namespace std;
    using namespace boost;
    cout << "milliseconds(1) = "
         <<  boost::chrono::milliseconds(1) << '\n';
    cout << "milliseconds(3) + microseconds(10) = "
         <<  boost::chrono::milliseconds(3) + boost::chrono::microseconds(10) << '\n';
    cout << "hours(3) + minutes(10) = "
         <<  boost::chrono::hours(3) + boost::chrono::minutes(10) << '\n';
    typedef boost::chrono::duration<long long, boost::ratio<1, 2500000000> > ClockTick;
    cout << "ClockTick(3) + boost::chrono::nanoseconds(10) = "
         <<  ClockTick(3) + boost::chrono::nanoseconds(10) << '\n';
   // ...
    return 0;
}

Вывод может быть

milliseconds(1) = 1 microsecond
milliseconds(3) + microseconds(10) = 3010 microseconds
hours(3) + minutes(10) = 190 minutes
ClockTick(3) + nanoseconds(10) = 56 [1/5000000000]seconds
Set cout to use short names:
milliseconds(3) + microseconds(10) = 3010 μs
hours(3) + minutes(10) = 190 m
ClockTick(3) + nanoseconds(10) = 56 [1/5000000000]s
system_clock::now() = 129387415616250000 [1/10000000]s since Jan 1, 1970
monotonic_clock::now() = 37297387636417 ns since boot
Set cout to use long names:
high_resolution_clock::now() = 37297387655134 nanoseconds since boot

Как видно, каждый тип длительности может передаваться без необходимости вручную транслировать единицы компиляционного времени после значения рабочего времени. А когда компиляционное устройство известно как «общая единица», используются английские названия. Для «необходимых единиц» имя единицы состоит из уменьшенного числителя и знаменателя ассоциированного ratio. Какие бы ни были настройки потока/локала для дуляция::rep используются для значения. Кроме того, когда значение 1, используются единичные формы для единиц.

Иногда желательно сократить эти имена, используя символы SI вместо префиксов SI. Это может быть достигнуто с использованием symbol_format манипулятор [1]:

cout << "\nSet cout to use short names:\n";
cout << boost::chrono::symbol_format;
cout << "milliseconds(3) + microseconds(10) = "
     <<  boost::chrono::milliseconds(3) + boost::chrono::microseconds(10) << '\n';
cout << "hours(3) + minutes(10) = "
     <<  boost::chrono::hours(3) + boost::chrono::minutes(10) << '\n';
cout << "ClockTick(3) + nanoseconds(10) = "
     <<  ClockTick(3) + boost::chrono::nanoseconds(10) << '\n';

Вывод может быть

Set cout to use short names:
milliseconds(3) + microseconds(10) = 3010 μs
hours(3) + minutes(10) = 190 m
ClockTick(3) + nanoseconds(10) = 56 [1/5000000000]s
system_clock::now() = 129387415616250000 [1/10000000]s since Jan 1, 1970
monotonic_clock::now() = 37297387636417 ns since boot
Set cout to use long names:
high_resolution_clock::now() = 37297387655134 nanoseconds since boot

μ для микросекунды определяется как U+00B5, кодируемый как UTF-8, UTF-16 или UTF-32 в зависимости от размера потока.

Когда решение о формате принимается во время выполнения, было бы лучше использовать параметризованный манипулятор duration_fmt как в

duration_style style;
//...
cout << duration_fmt(style);

Parsing a duration следует правилам, аналогичным duration преобразования конструктора. Значение и единица (символ или префиксированный) считываются из basic_istream. Если значение дурация имеет интегральное представление, то значение, выбранное в квадрате Производство (после преобразования в цель Производство единицы), то установлен Файлбит. Производство, основанное на представлениях с плавающей точкой, может быть парсировано с использованием любых единиц, которые не вызывают переполнения.

Например, поток, содержащий «5000 миллисекунд», может быть разделен на секунды, но если поток содержит «3001 мс», то выравнивание на секунды приведет к установлению failbit.

Пример:

#include <boost/chrono/chrono_io.hpp>
#include <sstream>
#include <cassert>
int main()
{
    using namespace std;
    istringstream in("5000 milliseconds 4000 ms 3001 ms");
    boost::chrono::seconds d(0);
    in >> d;
    assert(in.good());
    assert(d == seconds(5));
    in >> d;
    assert(in.good());
    assert(d == seconds(4));
    in >> d;
    assert(in.fail());
    assert(d == seconds(4));
    return 0;
}

Обратите внимание, что неудача duration может произойти в конце процесса анализа. Это означает, что персонажи, составляющие неудавшийся парс в потоке, обычно потребляются, несмотря на неспособность успешно парировать.

Иногда в шаблонном коде трудно знать, что такое единица вашей продолжительности. Все это детерминистское и инспектируемое. Но это может быть неудобно, особенно если вам просто нужно распечатать заявление об отладании. Например:

// round to nearest, to even on tie
template <class To, class Rep, class Period>
To
round(const duration<Rep, Period>& d)
{
    To t0 = duration_cast<To>(d);
    To t1 = t0;
    ++t1;
    auto diff0 = d - t0;
    cout << "diff0 = " << diff0 << '\n';
    auto diff1 = t1 - d;
    cout << "diff1 = " << diff1 << '\n';
    if (diff0 == diff1)
    {
        if (t0.count() & 1)
            return t1;
        return t0;
    }
    else if (diff0 < diff1)
        return t0;
    return t1;
}

Вот где I/O на протяжении всего времени действительно светит. Компилятор знает, что такое дифф0 и с этим предложением, что тип (с правильными единицами) будет автоматически напечатан для вас. Например:

milliseconds ms = round<milliseconds>(nanoseconds(123));  // diff0 = 123 nanoseconds
                                                          // diff1 = 999877 nanoseconds
milliseconds ms = round<milliseconds>(Ticks(44));         // diff0 = 2 [1/3000]seconds
                                                          // diff1 = 1 [1/3000]second

Этот простой I/O сделает продолжительность намного более доступной для программистов.

система_час является особенным. Это единственные часы, которые имеют преобразование между его Time_point и time_t. C впоследствии относится Time_t к Грегорскому календарю через ctime, gmtime, localtime и strftime. Ни C, ни POSIX не относятся к time_t к любому календарю, кроме Грегорского календаря. ISO 8601 указан только в терминах Грегорского календаря.

Boost.Chrono предоставляет систему_час:: Time_point I/O в виде григорианского календаря, и никакого другого календаря. Однако как система_час:: Time_point остается конвертируемым с time_t, клиенты могут создавать другие календари, которые взаимодействуют с time_t и впоследствии система_час::time_point.

Кроме того, существует практика для всех основных размещенных операционных систем хранения системного времени в формате, который облегчает отображение как Скоординированное универсальное время (UTC). Таким образом, Boost.Chrono обеспечивает, что выход по умолчанию для система_час::time_point будет в формате, который представляет точку во времени в отношении UTC.

cout << system_clock::now() << '\n';

может выводить

2011-09-15 18:36:59.325132 +0000

Этот формат сильно зависит от ISO 8601, но помещает «» между датой и временем вместо «T». Первый, кажется, более точно представляет существующую практику. Был выбран полностью цифровой формат, чтобы быть понятным как можно большему количеству читателей. По тем же причинам был выбран 24-часовой формат.

Из эталонных стандартов только ISO 8601 обсуждает выход дробных секунд. Ни C, ни POSIX не имеют встроенного функционала для этого. Однако, как представляется, универсальна (на основании этой статьи), что система_час::период является субсекундой. И, кажется, желательно, чтобы если вы вышли из потока система_час::time_point, вы могли бы направить его обратно и получить то же значение. Поэтому поток фракционных секунд (по крайней мере по умолчанию) кажется неизбежным.

Наконец, след «+0000» дезамбикирует UTC-форматированный система_час::time_point от одного формата в отношении локальной временной зоны компьютера. Последние могут быть легко достигнуты с помощью:

cout << time_fmt(local) << system_clock::now() << '\n';

это может привести к

2011-09-15 14:36:59.325132 -0400

Обратите внимание, что система_час::time_point сама по себе не является ни UTC, ни местное время. Однако на практике система_час::time_point - это количество клещей за некую эпоху, синхронизированное с UTC. Так как мобильный компьютер перемещается через часовые пояса, траверсаль часового пояса не влияет на значение система_час::time_point, произведенное система_час::now(). И только в форматировании его для потребления человеком можно выбрать UTC или местную часовую зону. C и POSIX относятся к time_t так же, как Boost.Chrono трактует system_ hour::time_point:

tm* gmtime(const time_t* timer) -> UTC
tm* localtime(const time_t* timer) -> local time

Это предложение просто расширяет C/POSIX time_t функциональность на C++ синтаксис и система_час::time_point.

time_fmt() манипулятор является «липким». Он останется в силе до тех пор, пока поток не разрушится или пока не изменится. Поток может быть сброшен в состояние по умолчанию с:

cout << time_fmt(utc);

И форматирование может быть дополнительно настроено с использованием последовательности форматов времени. Например:

cout << time_fmt(local, "%A %B %e, %Y %r");
cout << system_clock::now() << '\n';  // Sunday April 24, 2011 02:36:59 PM

При определении форматирования манипуляторов для широких потоков используйте широкие строки.

Вы можете использовать те же манипуляторы с istreams для указания последовательности паров.

К сожалению, нет никаких последовательностей форматирования / разделения, которые указывают на дробные секунды. Boost.Chrono не предоставляет таких последовательностей. В то же время можно форматировать и делить дробные секунды для системы_часа::time_point, по умолчанию формат, или путем использования пустой строки в time_fmt().

Текущая локализация потока может повлиять на последовательности парсинга/формата, поставляемые в систему_час:: Time_point манипуляторы (например, названия дней недели и названия месяцев).

В отличие от система_час::time_point, другие часы не имеют конверсии с time_t. Существует, вероятно, нет никакой связи между устойчивым_часовой::time_point и UTC вообще (UTC не является стабильным).

В целом, time_point отформатирован выводом своего внутреннего производства, за которым следует строка, описывающая time_point<119>::час эпоха. Эта строка будет варьироваться для каждого отдельного часа, и для каждой реализации поставленных часов.

#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
    cout << "steady_clock::now() = " << boost::chrono::steady_clock::now() << '\n';
#endif
    cout << "\nSet cout to use long names:\n"
            << boost::chrono::duration_long
            << "high_resolution_clock::now() = "
            << boost::chrono::high_resolution_clock::now() << '\n';

Вывод может быть

steady_clock::now() = 37297387636417 ns since boot
Set cout to use long names:
high_resolution_clock::now() = 37297387655134 nanoseconds since boot

Parsing a time_point включает в себя сначала выравнивание произведение, а затем выравнивание строки эпохи. Если строка эпохи не совпадает с строкой, связанной с time_point::час, то будет установлен отказ.

Пример:

#include <boost/chrono/chrono_io.hpp>
#include <sstream>
#include <iostream>
#include <cassert>
int main()
{
    using namespace std;
    boost::chrono::high_resolution_clock::time_point t0 = boost::chrono::high_resolution_clock::now();
    stringstream io;
    io << t0;
    boost::chrono::high_resolution_clock::time_point t1;
    io >> t1;
    assert(!io.fail());
    cout << io.str() << '\n';
    cout << t0 << '\n';
    cout << t1 << '\n';
    boost::chrono::high_resolution_clock::time_point t = boost::chrono::high_resolution_clock::now();
    cout << t << '\n';
    cout << "That took " << t - t0 << '\n';
    cout << "That took " << t - t1 << '\n';
    return 0;
}

Вывод может быть следующим:

50908679121461 nanoseconds since boot
That took 649630 nanoseconds

Вот простой пример, чтобы узнать, сколько часов компьютер был включен (на этой платформе):

#include <boost/chrono/chrono_io.hpp>
#include <iostream>
int main()
{
    using namespace std;
    using namespace boost;
    typedef boost::chrono::time_point<boost::chrono::steady_clock, boost::chrono::duration<double, boost::ratio<3600> > > T;
    T tp = boost::chrono::steady_clock::now();
    std::cout << tp << '\n';
    return 0;
}

Вывод может быть следующим:

17.8666 hours since boot

Интерфейс I/O, описанный в предыдущих разделах I/O, был на уровне пользователей. Эти услуги основаны на низкоуровневых услугах, которые полезны при написании библиотек. Услуги низкого уровня связаны с доступом к связанным ios State и местным граням. Дизайн следует стандартному дизайну C++ IOStreams:

Библиотека инкапсулирует локально-зависимую парсию и форматирование дукция в новый граничный класс. Давайте сосредоточимся на форматировании в этом примере. Заинтересованный гранд-класс duration_put, аналогичен времени_пути, день_подача и т.д.

Использование этой грани похоже на грань Time_put.

Далее мы покажем, как переопределить дурацию по умолчанию конструктор сделать все, что вы хотите (в этом случае установите его на ноль). Все, что нам нужно сделать, это изменить представление

namespace I_dont_like_the_default_duration_behavior {
template <class R>
class zero_default
{
public:
    typedef R rep;
private:
    rep rep_;
public:
    zero_default(rep i = 0) : rep_(i) {}
    operator rep() const {return rep_;}
    zero_default& operator+=(zero_default x) {rep_ += x.rep_; return *this;}
    zero_default& operator-=(zero_default x) {rep_ -= x.rep_; return *this;}
    zero_default& operator*=(zero_default x) {rep_ *= x.rep_; return *this;}
    zero_default& operator/=(zero_default x) {rep_ /= x.rep_; return *this;}
    zero_default  operator+ () const {return *this;}
    zero_default  operator- () const {return zero_default(-rep_);}
    zero_default& operator++()       {++rep_; return *this;}
    zero_default  operator++(int)    {return zero_default(rep_++);}
    zero_default& operator--()       {--rep_; return *this;}
    zero_default  operator--(int)    {return zero_default(rep_--);}
    friend zero_default operator+(zero_default x, zero_default y) {return x += y;}
    friend zero_default operator-(zero_default x, zero_default y) {return x -= y;}
    friend zero_default operator*(zero_default x, zero_default y) {return x *= y;}
    friend zero_default operator/(zero_default x, zero_default y) {return x /= y;}
    friend bool operator==(zero_default x, zero_default y) {return x.rep_ == y.rep_;}
    friend bool operator!=(zero_default x, zero_default y) {return !(x == y);}
    friend bool operator< (zero_default x, zero_default y) {return x.rep_ < y.rep_;}
    friend bool operator<=(zero_default x, zero_default y) {return !(y < x);}
    friend bool operator> (zero_default x, zero_default y) {return y < x;}
    friend bool operator>=(zero_default x, zero_default y) {return !(x < y);}
};
typedef boost::chrono::duration<zero_default<long long>, boost::nano        > nanoseconds;
typedef boost::chrono::duration<zero_default<long long>, boost::micro       > microseconds;
typedef boost::chrono::duration<zero_default<long long>, boost::milli       > milliseconds;
typedef boost::chrono::duration<zero_default<long long>                      > seconds;
typedef boost::chrono::duration<zero_default<long long>, boost::ratio<60>   > minutes;
typedef boost::chrono::duration<zero_default<long long>, boost::ratio<3600> > hours;
}

Использование

using namespace I_dont_like_the_default_duration_behavior;
milliseconds ms;
std::cout << ms.count() << '\n';

См. исходный файл example/i_dont_like_the_default_duration_behavior.cpp

Разработан «насыщенный» подписанный интегральный тип. Этот тип имеет +/- бесконечность и NaN (как плавающая точка IEEE), но в противном случае подчиняется подписанной интегральной арифметике. Этот класс впоследствии используется в качестве параметра шаблона Rep в бульваре::chrono::duration, чтобы продемонстрировать класс продолжительности, который не молча игнорирует переполненность.

См. исходный файл example/saturating.cpp

Пример утилита round_up: конвертирует d в To, округляя для неактуальных конверсий Возможность easily написать эту функцию является основной особенностью!

#include <boost/chrono.hpp>
#include <boost/type_traits.hpp>
#include <iostream>
template <class To, class Rep, class Period>
To
round_up(boost::chrono::duration<Rep, Period> d)
{
    To result = boost::chrono::duration_cast<To>(d);
    if (result < d)
        ++result;
    return result;
}

Чтобы продемонстрировать взаимодействие с xtime-подобным объектом:

struct xtime
{
    long sec;
    unsigned long usec;
};
template <class Rep, class Period>
xtime
to_xtime_truncate(boost::chrono::duration<Rep, Period> d)
{
    xtime xt;
    xt.sec = static_cast<long>(boost::chrono::duration_cast<seconds>(d).count());
    xt.usec = static_cast<long>(boost::chrono::duration_cast<microseconds>(d - seconds(xt.sec)).count());
    return xt;
}
template <class Rep, class Period>
xtime
to_xtime_round_up(boost::chrono::duration<Rep, Period> d)
{
    xtime xt;
    xt.sec = static_cast<long>(boost::chrono::duration_cast<seconds>(d).count());
    xt.usec = static_cast<unsigned long>(round_up<boost::chrono::microseconds>(d - boost::chrono::seconds(xt.sec)).count());
    return xt;
}
microseconds
from_xtime(xtime xt)
{
    return boost::chrono::seconds(xt.sec) + boost::chrono::microseconds(xt.usec);
}
void print(xtime xt)
{
    std::cout << '{' << xt.sec << ',' << xt.usec << "}\n";
}

Использование

xtime xt = to_xtime_truncate(seconds(3) + boost::chrono::milliseconds(251));
print(xt);
boost::chrono::milliseconds ms = boost::chrono::duration_cast<boost::chrono::milliseconds>(from_xtime(xt));
std::cout << ms.count() << " milliseconds\n";
xt = to_xtime_round_up(ms);
print(xt);
xt = to_xtime_truncate(boost::chrono::seconds(3) + nanoseconds(999));
print(xt);
xt = to_xtime_round_up(boost::chrono::seconds(3) + nanoseconds(999));
print(xt);

См. исходный файл xtime.cpp

Пользователи могут легко создавать свои часы, с обеими точками во времени и времени, которые имеют представление и точность по своему выбору. Например, если есть аппаратный счетчик, который просто увеличивает счет с каждым циклом cpu, можно очень легко построить часы, точки времени и продолжительность сверху, используя только несколько десятков строк кода. Такие системы могут быть использованы для вызова чувствительных к времени потоковых API, таких как сон, ожидание переменной состояния или ожидание блокировки мутекс. Предложенный здесь API не чувствителен к тому, является ли это 300 МГц (с периодом 3 1/3 наносекундного клеща) или 3 ГГц (с периодом клеща 1/3 наносекунды). И полученный код будет таким же эффективным, как если бы пользователь написал специальный часовой счетчик.

#include <boost/chrono.hpp>
#include <boost/type_traits.hpp>
#include <iostream>
template <long long speed>
struct cycle_count
{
    typedef typename boost::__ratio_multiply__<boost::ratio<speed>, boost::mega>::type
        frequency;  // Mhz
    typedef typename boost::__ratio_divide__<boost::ratio<1>, frequency>::type period;
    typedef long long rep;
    typedef boost::chrono::duration<rep, period> duration;
    typedef boost::chrono::time_point<cycle_count> time_point;
    static time_point now()
    {
        static long long tick = 0;
        // return exact cycle count
        return time_point(duration(++tick));  // fake access to clock cycle count
    }
};
template <long long speed>
struct approx_cycle_count
{
    static const long long frequency = speed * 1000000;  // MHz
    typedef nanoseconds duration;
    typedef duration::rep rep;
    typedef duration::period period;
    static const long long nanosec_per_sec = period::den;
    typedef boost::chrono::time_point<approx_cycle_count> time_point;
    static time_point now()
    {
        static long long tick = 0;
        // return cycle count as an approximate number of nanoseconds
        // compute as if nanoseconds is only duration in the std::lib
        return time_point(duration(++tick * nanosec_per_sec / frequency));
    }
};

См. исходный файл cycle_count.cpp

Этот пример демонстрирует использование пространственно-подобного структурирования для использования в качестве типа представления для обоих duration и time_point.

class xtime {
private:
    long tv_sec;
    long tv_usec;
    void fixup() {
        if (tv_usec < 0) {
            tv_usec += 1000000;
            --tv_sec;
        }
    }
public:
    explicit xtime(long sec, long usec) {
        tv_sec = sec;
        tv_usec = usec;
        if (tv_usec < 0 || tv_usec >= 1000000) {
            tv_sec += tv_usec / 1000000;
            tv_usec %= 1000000;
            fixup();
        }
    }
    explicit xtime(long long usec) {
        tv_usec = static_cast<long>(usec % 1000000);
        tv_sec  = static_cast<long>(usec / 1000000);
        fixup();
    }
    // explicit
    operator long long() const {return static_cast<long long>(tv_sec) * 1000000 + tv_usec;}
    xtime& operator += (xtime rhs) {
        tv_sec += rhs.tv_sec;
        tv_usec += rhs.tv_usec;
        if (tv_usec >= 1000000) {
            tv_usec -= 1000000;
            ++tv_sec;
        }
        return *this;
    }
    xtime& operator -= (xtime rhs) {
        tv_sec -= rhs.tv_sec;
        tv_usec -= rhs.tv_usec;
        fixup();
        return *this;
    }
    xtime& operator %= (xtime rhs) {
        long long t = tv_sec * 1000000 + tv_usec;
        long long r = rhs.tv_sec * 1000000 + rhs.tv_usec;
        t %= r;
        tv_sec = static_cast<long>(t / 1000000);
        tv_usec = static_cast<long>(t % 1000000);
        fixup();
        return *this;
    }
    friend xtime operator+(xtime x, xtime y) {return x += y;}
    friend xtime operator-(xtime x, xtime y) {return x -= y;}
    friend xtime operator%(xtime x, xtime y) {return x %= y;}
    friend bool operator==(xtime x, xtime y)
        { return (x.tv_sec == y.tv_sec && x.tv_usec == y.tv_usec); }
    friend bool operator<(xtime x, xtime y) {
        if (x.tv_sec == y.tv_sec)
            return (x.tv_usec < y.tv_usec);
        return (x.tv_sec < y.tv_sec);
    }
    friend bool operator!=(xtime x, xtime y) { return !(x == y); }
    friend bool operator> (xtime x, xtime y) { return y < x; }
    friend bool operator<=(xtime x, xtime y) { return !(y < x); }
    friend bool operator>=(xtime x, xtime y) { return !(x < y); }
    friend std::ostream& operator<<(std::ostream& os, xtime x)
        {return os << '{' << x.tv_sec << ',' << x.tv_usec << '}';}
};

Часы, основанные на пространственно-подобном строении.

class xtime_clock
{
public:
    typedef xtime                                  rep;
    typedef boost::micro                           period;
    typedef boost::chrono::duration<rep, period>   duration;
    typedef boost::chrono::time_point<xtime_clock> time_point;
    static time_point now()
    {
    #if defined(BOOST_CHRONO_WINDOWS_API)
        time_point t(duration(xtime(0)));
        gettimeofday((timeval*)&t, 0);
        return t;
    #elif defined(BOOST_CHRONO_MAC_API)
        time_point t(duration(xtime(0)));
        gettimeofday((timeval*)&t, 0);
        return t;
    #elif defined(BOOST_CHRONO_POSIX_API)
        //time_point t(0,0);
        timespec ts;
        ::clock_gettime( CLOCK_REALTIME, &ts );
        xtime xt( ts.tv_sec, ts.tv_nsec/1000);
        return time_point(duration(xt));
    #endif  // POSIX
    }
};

Использование xtime_hour

std::cout << "sizeof xtime_clock::time_point = " << sizeof(xtime_clock::time_point) << '\n';
std::cout << "sizeof xtime_clock::duration = " << sizeof(xtime_clock::duration) << '\n';
std::cout << "sizeof xtime_clock::rep = " << sizeof(xtime_clock::rep) << '\n';
xtime_clock::duration delay(boost::chrono::milliseconds(5));
xtime_clock::time_point start = xtime_clock::now();
while (xtime_clock::now() - start <= delay) {}
xtime_clock::time_point stop = xtime_clock::now();
xtime_clock::duration elapsed = stop - start;
std::cout << "paused " << boost::chrono::::nanoseconds(elapsed).count() << " nanoseconds\n";

См. исходный файл example/timeval_demo.cpp

Пользователь может определить функцию, возвращающую самые ранние time_point следующим образом:

template <class Clock, class Duration1, class Duration2>
typename boost::common_type<time_point<Clock, Duration1>,
                     time_point<Clock, Duration2> >::type
min(time_point<Clock, Duration1> t1, time_point<Clock, Duration2> t2)
{
    return t2 < t1 ? t2 : t1;
}

Возможность easily написать эту функцию является основной особенностью!

BOOST_AUTO(t1, system_clock::now() + seconds(3));
BOOST_AUTO(t2, system_clock::now() + nanoseconds(3));
BOOST_AUTO(t3, min(t1, t2));

См. исходный файл example/min_time_point.cpp

#include <boost/chrono.hpp>
#include <iostream>
#include <iomanip>
using namespace boost::chrono;
template< class Clock >
class timer
{
  typename Clock::time_point start;
public:
  timer() : start( Clock::now() ) {}
  typename Clock::duration elapsed() const
  {
    return Clock::now() - start;
  }
  double seconds() const
  {
    return elapsed().count() * ((double)Clock::period::num/Clock::period::den);
  }
};
int main()
{
  timer<system_clock> t1;
  timer<steady_clock> t2;
  timer<high_resolution_clock> t3;
  std::cout << "Type the Enter key: ";
  std::cin.get();
  std::cout << std::fixed << std::setprecision(9);
  std::cout << "system_clock-----------: "
            << t1.seconds() << " seconds\n";
  std::cout << "steady_clock--------: "
            << t2.seconds() << " seconds\n";
  std::cout << "high_resolution_clock--: "
            << t3.seconds() << " seconds\n";
  system_clock::time_point d4 = system_clock::now();
  system_clock::time_point d5 = system_clock::now();
  std::cout << "\nsystem_clock latency-----------: " << (d5 - d4).count() << std::endl;
  steady_clock::time_point d6 = steady_clock::now();
  steady_clock::time_point d7 = steady_clock::now();
  std::cout << "steady_clock latency--------: " << (d7 - d6).count() << std::endl;
  high_resolution_clock::time_point d8 = high_resolution_clock::now();
  high_resolution_clock::time_point d9 = high_resolution_clock::now();
  std::cout << "high_resolution_clock latency--: " << (d9 - d8).count() << std::endl;
  std::time_t now = system_clock::to_time_t(system_clock::now());
  std::cout << "\nsystem_clock::now() reports UTC is "
    << std::asctime(std::gmtime(&now)) << "\n";
  return 0;
}

Выход этой программы запуска выглядит так:

См. исходный файл example/await_keystroke.cpp

В приведенном выше примере мы пользуемся тем, что time_point преобразуют до тех пор, пока они имеют одни и те же часы, и до тех пор, пока их внутренний дукция преобразуется. Мы также пользуемся тем, что дуляция с плавающей точкой представления конвертируется из чего угодно. Наконец, система I/O обнаруживает более читаемую единицу «часов» для нашего duration<ДП,ratio<3600>.

Есть много других способов форматирования дуляция и Time_points. Например, см. ISO 8601. Вместо того, чтобы кодировать каждую возможность на оператор<, что привело бы к существенному кодовому раздутию даже для самых тривиальных применений, этот документ направлен на информирование читателя о том, как писать пользовательский I/O по желанию.

В качестве примера, функция ниже потоков произвольна дуляция к произвольному basic_ostreams с использованием формата:

[-]d/hh:mm:ss.cc

Где:

  • d - число days
  • h - число часов
  • m - число минут
  • ss.cc - число секунд округлено до ближайшей сотни секунды
    1. включает в себя
    2. включить
    3. включить
// format duration as [-]d/hh::mm::ss.cc
template <class CharT, class Traits, class Rep, class Period>
std::basic_ostream<CharT, Traits>&
display(std::basic_ostream<CharT, Traits>& os,
        boost::chrono::duration<Rep, Period> d)
{
    using namespace std;
    using namespace boost;
    typedef boost::chrono::duration<long long, boost::ratio<86400> > days;
    typedef boost::chrono::duration<long long, boost:centi> centiseconds;
    // if negative, print negative sign and negate
    if (d < boost::chrono::duration<Rep, Period>(0))
    {
        d = -d;
        os << '-';
    }
    // round d to nearest centiseconds, to even on tie
    centiseconds cs = boost::chrono::duration_cast<centiseconds>(d);
    if (d - cs > boost::chrono::milliseconds(5)
        || (d - cs == boost::chrono::milliseconds(5) && cs.count() & 1))
        ++cs;
    // separate seconds from centiseconds
    boost::chrono::seconds s = boost::chrono::duration_cast<boost::chrono::seconds>(cs);
    cs -= s;
    // separate minutes from seconds
    boost::chrono::minutes m = boost::chrono::duration_cast<boost::chrono::minutes>(s);
    s -= m;
    // separate hours from minutes
    boost::chrono::hours h = boost::chrono::duration_cast<boost::chrono::hours>(m);
    m -= h;
    // separate days from hours
    days dy = boost::chrono::duration_cast<days>(h);
    h -= dy;
    // print d/hh:mm:ss.cc
    os << dy.count() << '/';
    if (h < boost::chrono::hours(10))
        os << '0';
    os << h.count() << ':';
    if (m < boost::chrono::minutes(10))
        os << '0';
    os << m.count() << ':';
    if (s < boost::chrono::seconds(10))
        os << '0';
    os << s.count() << '.';
    if (cs < boost::chrono::centiseconds(10))
        os << '0';
    os << cs.count();
    return os;
}
int main()
{
    using namespace std;
    using namespace boost;
    display(cout, boost::chrono::steady_clock::now().time_since_epoch()
                  + boost::chrono::duration<long, boost::mega>(1)) << '\n';
    display(cout, -boost::chrono::milliseconds(6)) << '\n';
    display(cout, boost::chrono::duration<long, boost::mega>(1)) << '\n';
    display(cout, -boost::chrono::duration<long, boost::mega>(1)) << '\n';
}

Вывод может быть следующим:

12/06:03:22.95
-0/00:00:00.01
11/13:46:40.00
-11/13:46:40.00

Стандартная библиотека C++ 11 требует способности иметь дело с представлением времени в соответствии с современными практиками C++. Далее идет моделирование этого интерфейса.

Нечленные функции сна могут быть эмулированы следующим образом:

namespace boost { namespace this_thread {
template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d) {
    chrono::microseconds t = chrono::duration_cast<chrono::microseconds>(d);
    if (t < d)
        ++t;
    if (t > chrono::microseconds(0))
        std::cout << "sleep_for " << t.count() << " microseconds\n";
}
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& t) {
    using namespace chrono;
    typedef time_point<Clock, Duration> Time;
    typedef system_clock::time_point SysTime;
    if (t > Clock::now()) {
        typedef typename common_type<typename Time::duration,
                                     typename SysTime::duration>::type D;
        /* auto */ D d = t - Clock::now();
        microseconds us = duration_cast<microseconds>(d);
        if (us < d)
            ++us;
        SysTime st = system_clock::now() + us;
        std::cout << "sleep_until    ";
        detail::print_time(st);
        std::cout << " which is " << (st - system_clock::now()).count() << " microseconds away\n";
    }
}
}}

Следующий boost::thread::timed_mutex измененные функции

namespace boost {
struct timed_mutex {
    // ...
    template <class Rep, class Period>
    bool try_lock_for(const chrono::duration<Rep, Period>& d) {
        chrono::microseconds t = chrono::duration_cast<chrono::microseconds>(d);
        if (t <= chrono::microseconds(0))
            return try_lock();
        std::cout << "try_lock_for " << t.count() << " microseconds\n";
        return true;
    }
    template <class Clock, class Duration>
    bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
    {
        using namespace chrono;
        typedef time_point<Clock, Duration> Time;
        typedef system_clock::time_point SysTime;
        if (t <= Clock::now())
            return try_lock();
        typedef typename common_type<typename Time::duration,
          typename Clock::duration>::type D;
        /* auto */ D d = t - Clock::now();
        microseconds us = duration_cast<microseconds>(d);
        SysTime st = system_clock::now() + us;
        std::cout << "try_lock_until ";
        detail::print_time(st);
        std::cout << " which is " << (st - system_clock::now()).count()
          << " microseconds away\n";
        return true;
    }
};
}

boost::thread:: кондиционирование_variable функция, связанная со временем, изменена следующим образом:

namespace boost {
struct condition_variable
{
    // ...
    template <class Rep, class Period>
    bool wait_for(mutex&, const chrono::duration<Rep, Period>& d) {
        chrono::microseconds t = chrono::duration_cast<chrono::microseconds>(d);
        std::cout << "wait_for " << t.count() << " microseconds\n";
        return true;
    }
    template <class Clock, class Duration>
    bool wait_until(mutex&, const chrono::time_point<Clock, Duration>& t) {
        using namespace boost::chrono;
        typedef time_point<Clock, Duration> Time;
        typedef system_clock::time_point SysTime;
        if (t <= Clock::now())
            return false;
        typedef typename common_type<typename Time::duration,
          typename Clock::duration>::type D;
        /* auto */ D d = t - Clock::now();
        microseconds us = duration_cast<microseconds>(d);
        SysTime st = system_clock::now() + us;
         std::cout << "wait_until     ";
        detail::print_time(st);
        std::cout << " which is " << (st - system_clock::now()).count()
          << " microseconds away\n";
        return true;
    }
};
}

Далее следует, насколько просто использование этих функций:

boost::mutex m;
boost::timed_mutex mut;
boost::condition_variable cv;
using namespace boost;
this_thread::sleep_for(chrono::seconds(3));
this_thread::sleep_for(chrono::nanoseconds(300));
chrono::system_clock::time_point time_limit = chrono::system_clock::now() + chrono::__seconds_(4) + chrono::milliseconds(500);
this_thread::sleep_until(time_limit);
mut.try_lock_for(chrono::milliseconds(30));
mut.try_lock_until(time_limit);
cv.wait_for(m, chrono::minutes(1));    // real code would put this in a loop
cv.wait_until(m, time_limit);  // real code would put this in a loop
// For those who prefer floating-point
this_thread::sleep_for(chrono::duration<double>(0.25));
this_thread::sleep_until(chrono::system_clock::now() + chrono::duration<double>(1.5));

См. исходный файл example/simulated_thread_interface_demo.cpp

IO

Пример использования выходных данных на французском языке

#include <boost/chrono/chrono_io.hpp>
#include <iostream>
#include <locale>
int main()
{
    using namespace std;
    using namespace boost;
    using namespace boost::chrono;
    cout.imbue(locale(locale(), new duration_punct<char>
        (
            duration_punct<char>::use_long,
            "secondes", "minutes", "heures",
            "s", "m", "h"
        )));
    hours h(5);
    minutes m(45);
    seconds s(15);
    milliseconds ms(763);
    cout << h << ", " << m << ", " << s << " et " << ms << '\n';
}

Результат:

5 heures, 45 minutes, 15 secondes et 763 millisecondes

См. исходный файл example/french.cpp

C++ Standards Committee's current Working Paper

Наиболее авторитетным справочным материалом для библиотеки является текущий рабочий документ Комитета по стандартам C++ (WP). 20.11 Временные утилиты "время"

N2661 - A Foundation to Sleep On

От Говарда Э. Хиннанта, Уолтера Э. Брауна, Джеффа Гарланда и Марка Патерно. Является очень информативным и обеспечивает мотивацию ключевых дизайнерских решений

LGW 934. duration is missing operator%

Из Терри Голубиевски. Является очень информативным и обеспечивает мотивацию ключевых дизайнерских решений

LGW 935. clock error handling needs to be specified

От Бемана Доуса. Этот вопрос был назван NAD Future.


PrevUpHomeNext

Статья User's Guide раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 7. Boost.Chrono 2.0.5 может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Chapter 7. Boost.Chrono 2.0.5 ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 21:37:58/0.03048300743103/0