Boost C++ Libraries: Ticket #10967: Timed wait points inconsistently convert relative to absolute waits https://svn.boost.org/trac10/ticket/10967 <p> Possibly related: <a class="closed ticket" href="https://svn.boost.org/trac10/ticket/6787" title="#6787: Bugs: boost::thread::sleep() hangs if system time is rolled back (closed: fixed)">#6787</a> </p> <p> Stepping through the Boost.Thread win32 implementation, interruptible_wait() and non_interruptible_wait() are capable of accepting both relative and absolute timeouts. However condition_variable and thread join are always implemented as absolute timeouts, while thread sleep is always implemented as relative timeouts. I also see that timed mutex always converts absolute to relative too on win32. </p> <p> These all should be fixed to correctly use either relative or absolute timeouts as requested by the user, firstly at the upper layers where necessary. Then all waits on Windows always need to go via interruptible_wait() or non_interruptible_wait() as appropriate as these implement the proper calls on Windows for absolute deadline timers when absolute timeouts are requested. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/10967 Trac 1.4.3 viboes Sun, 25 Jan 2015 09:09:33 GMT owner, status changed https://svn.boost.org/trac10/ticket/10967#comment:1 https://svn.boost.org/trac10/ticket/10967#comment:1 <ul> <li><strong>owner</strong> changed from <span class="trac-author">Anthony Williams</span> to <span class="trac-author">viboes</span> </li> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">assigned</span> </li> </ul> <p> Thanks for pointing out this incoherency. I will check this asap. </p> Ticket viboes Sun, 25 Jan 2015 10:06:58 GMT <link>https://svn.boost.org/trac10/ticket/10967#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10967#comment:2</guid> <description> <p> I've created a branch to fix this issue </p> <p> <a class="ext-link" href="https://github.com/boostorg/thread/tree/fix/10967_inconsistent_abs_rel_time"><span class="icon">​</span>https://github.com/boostorg/thread/tree/fix/10967_inconsistent_abs_rel_time</a> </p> <p> Niall, I'm unable to check it. Would you like that I commit some changes I think that could be done, or do you prefer I post them here? </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 25 Jan 2015 10:10:08 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/10967#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10967#comment:3</guid> <description> <p> E.g. it would be better to rename do_try_join_until to do_try_join_for. This would not fix anything, but it will make things clearer. </p> <pre class="wiki">diff --git a/include/boost/thread/detail/thread.hpp b/include/boost/thread/detail/thread.hpp index b80eacf..2774eb0 100644 --- a/include/boost/thread/detail/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -472,7 +472,7 @@ namespace boost bool try_join_for(const chrono::duration&lt;Rep, Period&gt;&amp; rel_time) { chrono::milliseconds rel_time2= chrono::ceil&lt;chrono::milliseconds&gt;(rel_time); - return do_try_join_until(rel_time2.count()); + return do_try_join_for(rel_time2.count()); } #else template &lt;class Rep, class Period&gt; @@ -504,19 +504,16 @@ namespace boost #endif #if defined(BOOST_THREAD_PLATFORM_WIN32) private: - bool do_try_join_until_noexcept(uintmax_t milli, bool&amp; res); - inline bool do_try_join_until(uintmax_t milli); + bool do_try_join_for_noexcept(uintmax_t milli, bool&amp; res); + inline bool do_try_join_for(uintmax_t milli); public: bool timed_join(const system_time&amp; abs_time); - //{ - // return do_try_join_until(get_milliseconds_until(wait_until)); - //} #ifdef BOOST_THREAD_USES_CHRONO bool try_join_until(const chrono::time_point&lt;chrono::system_clock, chrono::nanoseconds&gt;&amp; tp) { chrono::milliseconds rel_time= chrono::ceil&lt;chrono::milliseconds&gt;(tp-chrono::system_clock::now()); - return do_try_join_until(rel_time.count()); + return do_try_join_for(rel_time.count()); } #endif @@ -769,9 +766,6 @@ namespace boost #ifdef BOOST_THREAD_PLATFORM_PTHREAD bool thread::do_try_join_until(struct timespec const &amp;timeout) -#else - bool thread::do_try_join_until(uintmax_t timeout) -#endif { if (this_thread::get_id() == get_id()) boost::throw_exception(thread_resource_error(static_cast&lt;int&gt;(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself")); @@ -788,6 +782,25 @@ namespace boost ); } } +#else + bool thread::do_try_join_for(uintmax_t timeout) + { + if (this_thread::get_id() == get_id()) + boost::throw_exception(thread_resource_error(static_cast&lt;int&gt;(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself")); + bool res; + if (do_try_join_for_noexcept(timeout, res)) + { + return res; + } + else + { + BOOST_THREAD_THROW_ELSE_RETURN( + (thread_resource_error(static_cast&lt;int&gt;(system::errc::invalid_argument), "boost thread: thread not joinable")), + false + ); + } + } +#endif #if !defined(BOOST_NO_IOSTREAM) &amp;&amp; defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template&lt;class charT, class traits&gt; diff --git a/src/win32/thread.cpp b/src/win32/thread.cpp index e02124f..2d9af0e 100644 --- a/src/win32/thread.cpp +++ b/src/win32/thread.cpp @@ -44,7 +44,7 @@ #include &lt;wrl\ftm.h&gt; #include &lt;windows.system.threading.h&gt; #pragma comment(lib, "runtimeobject.lib") -#endif +#endif namespace boost { @@ -198,7 +198,7 @@ namespace boost namespace detail { std::atomic_uint threadCount; - + bool win32::scoped_winrt_thread::start(thread_func address, void *parameter, unsigned int *thrdId) { Microsoft::WRL::ComPtr&lt;ABI::Windows::System::Threading::IThreadPoolStatics&gt; threadPoolFactory; @@ -220,7 +220,7 @@ namespace boost m_completionHandle = completionHandle; // Create new work item. - Microsoft::WRL::ComPtr&lt;ABI::Windows::System::Threading::IWorkItemHandler&gt; workItem = + Microsoft::WRL::ComPtr&lt;ABI::Windows::System::Threading::IWorkItemHandler&gt; workItem = Microsoft::WRL::Callback&lt;Microsoft::WRL::Implements&lt;Microsoft::WRL::RuntimeClassFlags&lt;Microsoft::WRL::ClassicCom&gt;, ABI::Windows::System::Threading::IWorkItemHandler, Microsoft::WRL::FtmBase&gt;&gt; ([address, parameter, completionHandle](ABI::Windows::Foundation::IAsyncAction *) { @@ -346,7 +346,7 @@ namespace boost return true; #endif } - + bool thread::start_thread_noexcept(const attributes&amp; attr) { #if BOOST_PLAT_WINDOWS_RUNTIME @@ -367,7 +367,7 @@ namespace boost return true; #endif } - + thread::thread(detail::thread_data_ptr data): thread_info(data) {} @@ -469,10 +469,10 @@ namespace boost #if defined BOOST_THREAD_USES_DATETIME bool thread::timed_join(boost::system_time const&amp; wait_until) { - return do_try_join_until(get_milliseconds_until(wait_until)); + return do_try_join_for(get_milliseconds_until(wait_until)); } #endif - bool thread::do_try_join_until_noexcept(uintmax_t milli, bool&amp; res) + bool thread::do_try_join_for_noexcept(uintmax_t milli, bool&amp; res) { detail::thread_data_ptr local_thread_info=(get_thread_info)(); if(local_thread_info) </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 25 Jan 2015 10:12:08 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/10967#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10967#comment:4</guid> <description> <p> The following code seems to be using do_wait incorrectly, it gives a relative instead of an absolute time, isn't it? </p> <pre class="wiki"> template &lt;class Clock, class Duration&gt; cv_status wait_until( unique_lock&lt;mutex&gt;&amp; lock, const chrono::time_point&lt;Clock, Duration&gt;&amp; t) { using namespace chrono; chrono::time_point&lt;Clock, Duration&gt; now = Clock::now(); if (t&lt;=now) { return cv_status::timeout; } do_wait(lock, ceil&lt;milliseconds&gt;(t-now).count()); return Clock::now() &lt; t ? cv_status::no_timeout : cv_status::timeout; } template &lt;class Rep, class Period&gt; cv_status wait_for( unique_lock&lt;mutex&gt;&amp; lock, const chrono::duration&lt;Rep, Period&gt;&amp; d) { using namespace chrono; if (d&lt;=chrono::duration&lt;Rep, Period&gt;::zero()) { return cv_status::timeout; } steady_clock::time_point c_now = steady_clock::now(); do_wait(lock, ceil&lt;milliseconds&gt;(d).count()); return steady_clock::now() - c_now &lt; d ? cv_status::no_timeout : cv_status::timeout; } </pre> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 25 Jan 2015 10:14:08 GMT</pubDate> <title>owner, status changed https://svn.boost.org/trac10/ticket/10967#comment:5 https://svn.boost.org/trac10/ticket/10967#comment:5 <ul> <li><strong>owner</strong> changed from <span class="trac-author">viboes</span> to <span class="trac-author">Niall Douglas</span> </li> <li><strong>status</strong> <span class="trac-field-old">assigned</span> → <span class="trac-field-new">new</span> </li> </ul> Ticket viboes Sun, 25 Jan 2015 10:17:44 GMT <link>https://svn.boost.org/trac10/ticket/10967#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10967#comment:6</guid> <description> <p> I've just seen your post. Adding the references you have identified here </p> <p> Some references to code: </p> <p> Always uses absolute: <a class="ext-link" href="https://github.com/boostorg/thread/blob/develop/include/boost/thread/win32/condition_variable.hpp#L92"><span class="icon">​</span>https://github.com/boostorg/thread/blob/develop/include/boost/thread/win32/condition_variable.hpp#L92</a> </p> <p> Always uses relative: <a class="ext-link" href="https://github.com/boostorg/thread/blob/develop/include/boost/thread/win32/basic_timed_mutex.hpp#L190"><span class="icon">​</span>https://github.com/boostorg/thread/blob/develop/include/boost/thread/win32/basic_timed_mutex.hpp#L190</a> </p> <p> Always uses relative: <a class="ext-link" href="https://github.com/boostorg/thread/blob/develop/include/boost/thread/v2/thread.hpp#L60"><span class="icon">​</span>https://github.com/boostorg/thread/blob/develop/include/boost/thread/v2/thread.hpp#L60</a> </p> <p> Always uses absolute: <a class="ext-link" href="https://github.com/boostorg/thread/blob/develop/include/boost/thread/detail/thread.hpp#L551"><span class="icon">​</span>https://github.com/boostorg/thread/blob/develop/include/boost/thread/detail/thread.hpp#L551</a> </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Niall Douglas</dc:creator> <pubDate>Sun, 25 Jan 2015 16:44:05 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/10967#comment:7 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10967#comment:7</guid> <description> <p> I think the API naming is indeed confusing. We have four situations for timed waits: </p> <ol><li>Wait until the system clock says some hour and date. If the system clock is adjusted, I want my wait adjusted. This is the same as wait_until(system_clock). </li></ol><ol start="2"><li>Wait until the steady clock has some deadline value. Adjustments of system clock have no effect. This is the same as wait_until(steady_clock). </li></ol><ol start="3"><li>Wait for X ticks of the steady clock to occur. Adjustments of system clock have no effect. This is the same as wait_for(steady_clock). </li></ol><ol start="4"><li>From my reading of the C++ standard, wait_for(system_clock) is considered to be invalid. A static assert should probably be generated here. </li></ol><p> I think we need four uniquely named APIs for each of these scenarios or four clearly named template function specialisations for both POSIX and Windows. All timed waits anywhere in Boost.Thread go through one of those four functions. Each API needs to take a parameter, or be named differently, to indicate whether it is interruptible or not. </p> <p> All the legacy timed wait functions need to be converted into one of these four wait APIs too. Personally speaking I think it is time to mandatory Chrono instead of making it optional. </p> <p> Obviously this is quite a bit of work. But it serves no one well if someone presses suspend on their computer and when they wake it up all their Boost applications have hanged :( </p> <p> I was originally given a few paid hours to look into the condvar problem on Windows. I may be able to ask for more hours to fix more widely, then I can help you out more than just on Windows if you need me for that. In particular I think we need some extra tests which verify all this works correctly. </p> <p> Niall </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Sun, 25 Jan 2015 16:58:09 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/10967#comment:8 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10967#comment:8</guid> <description> <p> Point 4 has no sens. duration is not dependent on any clock. </p> <p> I don't see why we would need the 3 API. Each platform could provide only one of them. E.g. pthread provides only wait having as parameter the an absolute time. </p> <p> I'm not for breaking the user interface. Users that didn't linked with Chrono, shouldn't do it no if they don't use it. </p> <p> I agree for fixing all this stuff if the result is alway backward compatible (Or having the consensus that Boost.Thread can break user code on the Boost ML). </p> <p> If you want to work on a clean Boost.Thread implementation I suggest you to contribute on a new completely separated version V5 for C++11 compilers as I plan to do. Are you interested? </p> <p> Agreed for the test. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Niall Douglas</dc:creator> <pubDate>Sun, 25 Jan 2015 19:34:49 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/10967#comment:9 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10967#comment:9</guid> <description> <p> Replying to <a class="ticket" href="https://svn.boost.org/trac10/ticket/10967#comment:8" title="Comment 8">viboes</a>: </p> <blockquote class="citation"> <p> I don't see why we would need the 3 API. Each platform could provide only one of them. E.g. pthread provides only wait having as parameter the an absolute time. </p> </blockquote> <p> They would only be internal API. Public code cannot see them. </p> <p> My reason is because if you unify all the timed wait logic into a single location for all of Thread instead of each threading primitive doing its own thing, it makes it much easier to debug, coordinate and extend into the future. For example, if you implement a timed_wait_for_any(future) it is using identical timed wait code to timed_mutex. </p> <p> Sure, on POSIX all three functions convert into pthread absolute timed waits. But it is an API abstraction to help maintenance, that's all. </p> <blockquote class="citation"> <p> I agree for fixing all this stuff if the result is alway backward compatible (Or having the consensus that Boost.Thread can break user code on the Boost ML). </p> </blockquote> <p> The API I proposed is completely internal. </p> <blockquote class="citation"> <p> If you want to work on a clean Boost.Thread implementation I suggest you to contribute on a new completely separated version V5 for C++11 compilers as I plan to do. Are you interested? </p> </blockquote> <p> I'll reply to that by private email. </p> <p> Niall </p> </description> <category>Ticket</category> </item> <item> <dc:creator>viboes</dc:creator> <pubDate>Mon, 02 Feb 2015 05:51:49 GMT</pubDate> <title>type changed https://svn.boost.org/trac10/ticket/10967#comment:10 https://svn.boost.org/trac10/ticket/10967#comment:10 <ul> <li><strong>type</strong> <span class="trac-field-old">Bugs</span> → <span class="trac-field-new">Tasks</span> </li> </ul> <p> After spending some time I don't see any bug here. Of course the code can be rewritten to be more clear. </p> <p> Moving to a Task until a bug is clearly identified. </p> Ticket viboes Tue, 14 Nov 2017 20:55:59 GMT <link>https://svn.boost.org/trac10/ticket/10967#comment:11 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/10967#comment:11</guid> <description> <p> Note that we are working on a branch that pretend to fix all time related issues. </p> </description> <category>Ticket</category> </item> </channel> </rss>