Boost C++ Libraries: Ticket #11331: boost::this_thread::sleep_for does not sleep for requested time https://svn.boost.org/trac10/ticket/11331 <p> boost::this_thread::sleep_for does not accurately sleep for the requested amount of time (+/- 30ms) on a Windows 7 x64 environment when the requested time is on the order of half a minute. std::this_thread::sleep_for is able to accurately sleep for the requested amount of time. Here is a sample program illustrating the issue: </p> <pre class="wiki">#include &lt;boost/thread.hpp&gt; #include &lt;boost/chrono.hpp&gt; #include &lt;chrono&gt; #include &lt;iostream&gt; #include &lt;thread&gt; void boostThreadFunction () { std::cout &lt;&lt; "Starting Boost thread" &lt;&lt; std::endl; for (int i = 0; i &lt; 10; ++i) { auto sleep_time = boost::chrono::milliseconds {29000 + 100 * i}; auto mark = std::chrono::steady_clock::now (); boost::this_thread::sleep_for (sleep_time); auto duration = std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;( std::chrono::steady_clock::now () - mark); std::cout &lt;&lt; "Boost thread:" &lt;&lt; std::endl; std::cout &lt;&lt; "\tSupposed to sleep for:\t" &lt;&lt; sleep_time.count () &lt;&lt; " ms" &lt;&lt; std::endl; std::cout &lt;&lt; "\tActually slept for:\t" &lt;&lt; duration.count () &lt;&lt; " ms" &lt;&lt; std::endl &lt;&lt; std::endl; } } void stdThreadFunction () { std::cout &lt;&lt; "Starting Std thread" &lt;&lt; std::endl; for (int i = 0; i &lt; 10; ++i) { auto sleep_time = std::chrono::milliseconds {29000 + 100 * i}; auto mark = std::chrono::steady_clock::now (); std::this_thread::sleep_for (sleep_time); auto duration = std::chrono::duration_cast&lt;std::chrono::milliseconds&gt;( std::chrono::steady_clock::now () - mark); std::cout &lt;&lt; "Std thread:" &lt;&lt; std::endl; std::cout &lt;&lt; "\tSupposed to sleep for:\t" &lt;&lt; sleep_time.count () &lt;&lt; " ms" &lt;&lt; std::endl; std::cout &lt;&lt; "\tActually slept for:\t" &lt;&lt; duration.count () &lt;&lt; " ms" &lt;&lt; std::endl &lt;&lt; std::endl; } } int main () { boost::thread boost_thread (&amp;boostThreadFunction); std::this_thread::sleep_for (std::chrono::seconds (10)); std::thread std_thread (&amp;stdThreadFunction); boost_thread.join (); std_thread.join (); system ("pause"); return 0; } </pre><p> Here is the output produced in my environment: </p> <pre class="wiki">Starting Boost thread Starting Std thread Boost thread: Supposed to sleep for: 29000 ms Actually slept for: 29690 ms Std thread: Supposed to sleep for: 29000 ms Actually slept for: 29009 ms Boost thread: Supposed to sleep for: 29100 ms Actually slept for: 29999 ms Std thread: Supposed to sleep for: 29100 ms Actually slept for: 29111 ms Boost thread: Supposed to sleep for: 29200 ms Actually slept for: 29990 ms Std thread: Supposed to sleep for: 29200 ms Actually slept for: 29172 ms Boost thread: Supposed to sleep for: 29300 ms Actually slept for: 30005 ms Std thread: Supposed to sleep for: 29300 ms Actually slept for: 29339 ms Boost thread: Supposed to sleep for: 29400 ms Actually slept for: 30003 ms Std thread: Supposed to sleep for: 29400 ms Actually slept for: 29405 ms Boost thread: Supposed to sleep for: 29500 ms Actually slept for: 29999 ms Std thread: Supposed to sleep for: 29500 ms Actually slept for: 29472 ms Boost thread: Supposed to sleep for: 29600 ms Actually slept for: 29999 ms Std thread: Supposed to sleep for: 29600 ms Actually slept for: 29645 ms Boost thread: Supposed to sleep for: 29700 ms Actually slept for: 29998 ms Std thread: Supposed to sleep for: 29700 ms Actually slept for: 29706 ms Boost thread: Supposed to sleep for: 29800 ms Actually slept for: 29998 ms Std thread: Supposed to sleep for: 29800 ms Actually slept for: 29807 ms Boost thread: Supposed to sleep for: 29900 ms Actually slept for: 30014 ms Std thread: Supposed to sleep for: 29900 ms Actually slept for: 29915 ms </pre><p> Looking at libs/thread/src/win32/thread.cpp, this inaccuracy may be by design; a +/-5% tolerance appears to be added to the wait time to take advantage of coalescing timers. See related <a class="missing wiki">StackOverflow</a> question: <a class="ext-link" href="http://stackoverflow.com/questions/30381866/boost-thread-wakes-up-too-late-in-1-58"><span class="icon">​</span>http://stackoverflow.com/questions/30381866/boost-thread-wakes-up-too-late-in-1-58</a> </p> <p> However, we are dependent on sleep_for() being as accurate as possible; for us, this is a breaking change. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/11331 Trac 1.4.3 viboes Fri, 22 May 2015 22:25:55 GMT owner changed https://svn.boost.org/trac10/ticket/11331#comment:1 https://svn.boost.org/trac10/ticket/11331#comment:1 <ul> <li><strong>owner</strong> changed from <span class="trac-author">Anthony Williams</span> to <span class="trac-author">Niall Douglas</span> </li> </ul> <p> Niall, I believe that you did this changes. Could you recall us why this was necessary? </p> Ticket Niall Douglas Sat, 23 May 2015 15:53:47 GMT <link>https://svn.boost.org/trac10/ticket/11331#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11331#comment:2</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/11331#comment:1" title="Comment 1">viboes</a>: </p> <blockquote class="citation"> <p> Niall, I believe that you did this changes. Could you recall us why this was necessary? </p> </blockquote> <p> Yep, this change was all me. </p> <p> The change was not my design however. boost-dev was asked for options, and this design was the consensus that emerged. I personally didn't agree with it, but there you go. I might add that just because we say that we don't mind a +/- 1 sec tolerance doesn't mean that Windows actually gives us that, it just /may/ give us up to that. </p> <p> A clamp on the upper bound of the tolerance was considered unnecessary precisely because the correct wakeup is specified to Windows, and whatever the next interrupt is will execute the timer. The tolerance is not automatic lateness, it's simply permission to increase variance past the system tick rate of ~30ms. That has huge benefits for battery operated devices, and it also helps catch buggy code like the OPs. </p> <p> Regarding this statement: </p> <p> Replying to <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/11331" title="#11331: Bugs: boost::this_thread::sleep_for does not sleep for requested time (closed: wontfix)">Scott Minor &lt;scott.minor@…&gt;</a>: </p> <blockquote class="citation"> <p> However, we are dependent on sleep_for() being as accurate as possible; for us, this is a breaking change. </p> </blockquote> <p> No, it is your algorithm which is broken. If your use depends on any accuracy at all from any STL11 timed wait implementation, your code is wrong and needs to be fixed. The C++ standard is very clear than you can expect no guarantees whatsoever in any timed sleep function (including any amount of actual sleep), and any code which is written to require accuracy is incorrect. I might add that the Microsoft STL may be likely to gain a similar timer design to Boost.Thread soon as I coordinated with Stephan what I was about to change in Boost.Thread. We're just earlier to ship, that's all. </p> <p> Now, that said, I personally speaking would just love if we could add timer hardness/softness support to the STL and very considerably strengthen those guarantees on platforms allowing it, but that's probably work best done in Boost.Thread v5 (and the associated changes in Boost.Chrono) as an early design imperative so the rewrite is timer hardness/softness friendly from the very beginning. </p> <p> Niall </p> </description> <category>Ticket</category> </item> <item> <author>scott.minor.13@…</author> <pubDate>Sun, 24 May 2015 04:48:17 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11331#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11331#comment:3</guid> <description> <p> Thanks for the follow-up. How would you recommend users of Boost 1.58 rewrite their algorithms if they are impacted by this behavior? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Niall Douglas</dc:creator> <pubDate>Sun, 24 May 2015 21:33:27 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11331#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11331#comment:4</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/11331#comment:3" title="Comment 3">scott.minor.13@…</a>: </p> <blockquote class="citation"> <p> Thanks for the follow-up. How would you recommend users of Boost 1.58 rewrite their algorithms if they are impacted by this behavior? </p> </blockquote> <p> Depends on the algorithm. 95% of the time if you need to wait for exactly 30 seconds down to the millisecond, there is something very wrong with your assumptions because that is only ever somewhat likely on a non-realtime OS, or any system able to swap memory onto disc. </p> <p> For example, if you actually merely need to poll something every thirty seconds, what you do is to adjust subsequent timeouts for when some timeout is late, and you aim for 120 wakeups per hour, not a sleep of 30 seconds each. You obviously need to adjust readings according to wakeup error. This is the kind of thing engineers ought to do from the beginning, but it's just hugely easier not to. </p> <p> Another strategy is you sleep 80% of 30 seconds, then enter a yield loop for another 10%, then a spin loop for the remaining 10% - this delivers microsecond accurate sleeps most of the time. For any occasions where the OS context switches at exactly the wrong moment you still need a method of detecting the error and throwing away/retrying the exact wait. </p> <p> Niall </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Fri, 29 May 2015 18:07:41 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11331#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11331#comment:5</guid> <description> <p> Could we close the issue as works as expected? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Mon, 01 Jun 2015 20:21:37 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11331#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11331#comment:6</guid> <description> <p> Niall, why do the boost dev list wanted the change? Have you a pointer, please? What issue was this change fixing? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Niall Douglas</dc:creator> <pubDate>Mon, 01 Jun 2015 23:42:41 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/11331#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/11331#comment:7</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/11331#comment:6" title="Comment 6">viboes</a>: </p> <blockquote class="citation"> <p> Niall, why do the boost dev list wanted the change? Have you a pointer, please? What issue was this change fixing? </p> </blockquote> <p> I believe the discussion began with <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/9856" title="#9856: Bugs: [windows] condition_variable::wait_for returns wrong cv_status on timeout. (closed: wontfix)">#9856</a> which contains links to the appropriate boost-dev threads. </p> <p> Niall </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 28 Jun 2015 09:39:04 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/11331#comment:8 https://svn.boost.org/trac10/ticket/11331#comment:8 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">wontfix</span> </li> </ul> Ticket