[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

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