{"id":111375,"date":"2025-07-14T07:00:00","date_gmt":"2025-07-14T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111375"},"modified":"2025-07-14T09:37:05","modified_gmt":"2025-07-14T16:37:05","slug":"20250714-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250714-00\/?p=111375","title":{"rendered":"There is a <CODE>std::<WBR>chrono::<WBR>high_<WBR>resolution_<WBR>clock<\/CODE>, but no <CODE>low_<WBR>resolution_<WBR>clock<\/CODE>"},"content":{"rendered":"<p>The C++ standard provides a <code>std::<wbr \/>chrono::<wbr \/>high_<wbr \/>resolution_<wbr \/>clock<\/code> which provides the implementation&#8217;s clock with the smallest tick period. This gives you the best resolution available to the implementation.<\/p>\n<p>But what if you don&#8217;t need the best resolution available to the implementation? For example, <a title=\"Adding delays to our task sequencer, part 3\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250404-00\/?p=111046\"> our task sequencer wants to wait one second<\/a>, but accuracy to the nearest 100 nanoseconds is not required. If it&#8217;s one second or 0.999 seconds or 1.1 seconds, they&#8217;re all good enough.<\/p>\n<p>In that case, I manually switched to the <code>Get\u00adTick\u00adCount64<\/code> timer, which has only millisecond resolution, and in practice is good only to the nearest timer tick, which will be more like 10 milliseconds. We are using the value to decide how long to sleep, and sleeps are already fairly sloppy, so trying to be accurate to the nearest nanosecond is pointless.<\/p>\n<p>What we need is a <code>cheap_<wbr \/>steady_<wbr \/>clock<\/code> that ticks steadily and doesn&#8217;t need the shortest tick period. Low cost is more important than precision.<\/p>\n<p>For Windows, this means using the <code>Get\u00adTick\u00adCount64<\/code> timer. Its millisecond resolution is plenty good enough for deciding how long to sleep, and the value is extremely cheap to obtain.<\/p>\n<pre>struct cheap_steady_clock\r\n{\r\n    using rep = int64_t;\r\n    using period = std::milli;\r\n    using duration = std::chrono::duration&lt;rep, period&gt;;\r\n    using time_point = std::chrono::time_point&lt;cheap_steady_clock&gt;;\r\n\r\n    static constexpr bool is_steady = true;\r\n\r\n    static time_point now() noexcept\r\n    {\r\n        return time_point{ duration{\r\n            static_cast&lt;int64_t&gt;(GetTickCount64()) } };\r\n    }\r\n};\r\n<\/pre>\n<p>I use a representation of <code>int64_t<\/code> so that negative durations are representable.<\/p>\n<p>For linux systems, you probably would use <code>CLOCK_<wbr \/>MONOTONIC_<wbr \/>COARSE<\/code>, which is documented as a &#8220;faster but less precise version of <code>CLOCK_<wbr \/>MONOTONIC<\/code>.&#8221; In practice, it is 1ms.<\/p>\n<pre>struct cheap_steady_clock\r\n{\r\n    using duration = std::chrono::nanoseconds;\r\n    using rep = duration::rep;\r\n    using period = duration::period;\r\n    using time_point = std::chrono::time_point&lt;cheap_steady_clock&gt;;\r\n\r\n    static constexpr bool is_steady = true;\r\n\r\n    static time_point now() noexcept\r\n    {\r\n        struct timespec tp;\r\n        if (0 != clock_gettime(CLOCK_MONOTONIC_COARSE, &amp;tp))\r\n            throw system_error(errno, \"clock_gettime(CLOCK_MONOTONIC_COARSE) failed\");\r\n        return time_point(std::chrono::seconds(tp.tv_sec) +\r\n                          std::chrono::nanoseconds(tp.tv_nsec));\r\n    }\r\n};\r\n<\/pre>\n<p>Note that the <code>now()<\/code> method is <code>noexcept<\/code> despite throwing an exception if it cannot read the time. The <code>noexcept<\/code> is required by the standard, so if we can&#8217;t read the time, we have no choice but to terminate the program.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For when you care only enough to be roughly on time.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-111375","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>For when you care only enough to be roughly on time.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111375","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=111375"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111375\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=111375"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111375"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111375"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}