Subject: [Boost-bugs] [Boost C++ Libraries] #8323: boost::thread::try_join_for/try_join_until may block indefinitely due to a combination of problems in Boost.Thread and Boost.Chrono
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2013-03-22 07:58:26
#8323: boost::thread::try_join_for/try_join_until may block indefinitely due to a
combination of problems in Boost.Thread and Boost.Chrono
------------------------------------------------------------------------------------------------+
Reporter: szakharchenko@⦠| Owner: anthonyw
Type: Bugs | Status: new
Milestone: To Be Determined | Component: thread
Version: Boost 1.50.0 | Severity: Problem
Keywords: thread, chrono, steady_clock, try_jon_for, try_join_until, QueryPerformanceCounter |
------------------------------------------------------------------------------------------------+
In the following, try_join_test may hang indefinitely (using Boost 1.50):
{{{#!c++
void very_busy_thread()
{
while (true) boost::this_thread::interruption_point();
}
void try_join_test()
{
boost::thread t(very_busy_thread);
for (int i=0;i<1000000;i++)
{
t.try_join_for(boost::chrono::milliseconds(0)); // This call may
hang indefinitely
}
t.interrupt();
t.join();
}
}}}
This has been reproduced on a real dual-core Intel Xeon system and also on
2 multicore virtual machines (one using VirtualBox, another with KVM).
Here's my (incomplete, possibly incorrect) analysis of the problem:
thread.try_join_for(boost::chrono::milliseconds(0)) called on thread which
is still running
{{{#!c++
bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
{
return try_join_until(chrono::steady_clock::now() + rel_time);
}
}}}
steady_clock comes into play, which calls QueryPerformanceCounter the
"steadiness" of which is disputable
here Clock is steady_clock
t = rep_ = 5591678518200
system_clock::time_point s_now = system_clock::now() =
rep_=130084071987844000;
typename Clock::time_point c_now = Clock::now() = rep_ = 5591679763370
which is LESS THAN t = rep_ = 5591678518200 (QueryPerformanceCounter says
hello)
try_join_until(s_now + ceil<nanoseconds>(t - c_now)) is called with a
system time in the PAST AND in a past ~1msec ago (possibly important!)
thread.cpp:342:
{{{#!c++
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-
chrono::system_clock::now());
}}}
rel_time becomes EXACTLY -1;
detail::timeout(uintmax_t milliseconds_) accepts a _signed_ integer,
converting it to a huge number;
target_time.is_sentinel() == false
target_time.remaining_milliseconds(), time_left.milliseconds >
min_timer_wait_period is false (thread.cpp:482)
using_timer == false (not using SetWaitableTimer)
target_time becomes detail::timeout(time_left.milliseconds) (a huge
number) (thread.cpp:501)
is_sentinel() returns true -> remaining_milliseconds returns
remaining_time(win32::infinite) (thread_data.hpp:151)
time_left.milliseconds becomes a large number
using_timer is false, time_left.milliseconds is used as timeout which is
huge
WaitForMultipleObjects waits for a nearly-infinite amount of time
-- Ticket URL: <https://svn.boost.org/trac/boost/ticket/8323> Boost C++ Libraries <http://www.boost.org/> Boost provides free peer-reviewed portable C++ source libraries.
This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:12 UTC