Re: [Boost-bugs] [Boost C++ Libraries] #9856: [windows] condition_variable::wait_for returns wrong cv_status on timeout.

Subject: Re: [Boost-bugs] [Boost C++ Libraries] #9856: [windows] condition_variable::wait_for returns wrong cv_status on timeout.
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2015-01-22 18:38:11


#9856: [windows] condition_variable::wait_for returns wrong cv_status on timeout.
-------------------------+-------------------------------------------------
  Reporter: pi88el@… | Owner: ned14
      Type: Bugs | Status: new
 Milestone: | Component: thread
   Version: Boost | Severity: Problem
  1.57.0 | Keywords: condition_variable wait_for
Resolution: | cv_status
-------------------------+-------------------------------------------------

Comment (by ned14):

 I have an update on this issue. Firstly, I have committed a testcase for
 this to Boost.Thread trunk, so it is now being tested as part of regular
 unit testing.

 I have some quite scary news though. Boost.Thread decides whether the wait
 has timed out by comparing steady_clock (really QueryPerformanceCounter)
 from before and after, and if the wait took the timeout or longer it
 assumes that timeout occurred. Unfortunately, WaitForMultipleObjectsEx()
 provides no guarantees that it actually waits for the timeout requested -
 you might request 50ms, but might actually get 10ms. Here is an example
 program:

 {{{
 #include <windows.h>
 #include <stdio.h>
 #include <chrono>

 int main(void)
 {
   ULONG ulDelay_ms = 20;
   HANDLE hSemaphoreDelay = CreateSemaphore(NULL, 0, 1, NULL);

   for (size_t n = 0; n < 50; n++)
   {
     while (1) {
       auto begin = std::chrono::high_resolution_clock::now();
       ULONG hr = WaitForSingleObject(hSemaphoreDelay, ulDelay_ms);
       auto end = std::chrono::high_resolution_clock::now();
       auto diff = end - begin;

       if (hr == WAIT_ABANDONED)
         printf("Wait Abandoned ");
       else if (hr == WAIT_TIMEOUT)
         printf("Timed out ");
       else
         printf("Signaled ");
       DWORD lTDelta =
 std::chrono::duration_cast<std::chrono::milliseconds>(diff).count();
       printf("Target Wait Interval: %u Real Wait Interval: %u (%u)\n",
 ulDelay_ms, lTDelta, diff.count());
       if (lTDelta >= ulDelay_ms) break;
     }
     printf("\n");
   }

   CloseHandle(hSemaphoreDelay);
   return 0;
 }
 }}}

 ... and indeed very occasionally it is returning after 16-18ms instead of
 the requested 20ms at the same frequency that Boost.Thread is not
 returning timeout.

 This is scary because I believe every single wait routine in Windows in
 Boost.Thread, and possibly other Boost libraries, will need to be audited
 and potentially refactored. I'll raise it on boost-dev tomorrow morning. I
 believe this new early timeout feature was probably introduced when
 Microsoft added timer coalescing to Windows to save battery on mobile
 devices, and so only appeared in Windows 7 and later. The fact it hasn't
 presented sooner is worrying.

 Niall

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/9856#comment:16>
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:17 UTC