Boost logo

Boost :

Subject: Re: [boost] [thread] Timed waits in Boost.Thread potentiallyfundamentally broken on Windows (possibly rest of Boost too)
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2015-01-24 14:56:37


On 24 Jan 2015 at 21:29, Andrey Semashev wrote:

> > The problem with the above strategy is that it was clearly designed
> > around when Windows had a fixed tick interval of 10ms multiples, the
> > kernel didn't coalesce timers and the kernel wasn't tickless.
>
> I'm not sure if that was done so in account for a specific time quant
> duration. My understanding is that this was mainly done for two
> reasons. First, to make shorter waits more efficient.

I can see that. Right now it creates a brand new waitable timer
object every single timed wait if the interval >= 20 ms. I would lazy
initialise and cache one in thread local data instead.

> Second, waitable
> timers take into account system time shifts, which is more important
> for longer waits.

They _optionally_ do yes. They can do relative as well as absolute
waits, and if the value was absolute then it is adjusted for system
clock shifts. Thread already has support for this.

> FWIW, as I remember Windows quant duration is
> adjustable both by user and application and by default on desktop is
> about 15 ms. So it makes little sense to aim for a specific quant
> value, much less a multiple of 10 ms.

The quant can be reduced to 0.9 ms, or be anywhere between 0.9 and
~15 ms and can change at any time.
 
> The optimization for shorter waits may not be relevant anymore, but in
> order to make the change for use of waitable timers for all absolute
> waits one should conduct some performance tests.

Agreed.

> And there's another consideration. Waitable timers are useful for
> absolute waits. For relative waits I would still like Boost.Thread to
> use relative system waits. The reason is that relative waits do not
> react to system time shifts and do not require a waitable timer kernel
> object.

This is interesting actually. The win32 interruptible_wait() and
uninterruptible_wait() functions consume a detail::timeout which is
capable of transferring either relative or absolute timeout. However
condition_variable timed wait and thread timed join never calls with
anything but an absolute deadline timeout, and converts all relative
to absolute. Oddly enough this_thread::sleep_until seems to convert
its absolute timeout to a relative one, and thunks through
this_thread::sleep_for, so here all absolutes are converted to
relative.

So we have the odd situation that 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.

Some of this isn't win32 specific either. I can see some code there
which looks like these are decisions being made by upper layers of
code and so would affect POSIX as well.

I've added this issue as
https://svn.boost.org/trac/boost/ticket/10967.

Some references to code:

Always uses absolute:
https://github.com/boostorg/thread/blob/develop/include/boost/thread/w
in32/condition_variable.hpp#L92

Always uses relative:
https://github.com/boostorg/thread/blob/develop/include/boost/thread/w
in32/basic_timed_mutex.hpp#L190

Always uses relative:
https://github.com/boostorg/thread/blob/develop/include/boost/thread/v
2/thread.hpp#L60

Always uses absolute:
https://github.com/boostorg/thread/blob/develop/include/boost/thread/d
etail/thread.hpp#L551

> > What I'm planning to do is very simple: we always use deadline timer
> > scheduling from now on, so quite literally the steady_clock deadline
> > that comes in is exactly that handed to Windows unmodified. I was
> > also going to try setting a tolerable delay via SetWaitableTimerEx()
> > on Vista and later where the tolerable delay is calculated as 10% of
> > the interval to the deadline but clamped to:
> >
> > timeGetTime() <= tolerable delay <= 250 ms
>
> I'm not sure I understood this. timeGetTime() returns system time
> since boot. Did you mean that you would somehow discover the quant
> duration and use it for the tolerable delay?

Sorry I was being sloppy. The current quantum is the
KiCyclesPerClockQuantum kernel variable. I believe there is a user
space function for that now ... a quick google search says
GetSystemTimeAdjustment(). He literally reads from a memory location
in the kernel, so it's as quick as reading a variable.

Niall

-- 
ned Productions Limited Consulting
http://www.nedproductions.biz/ 
http://ie.linkedin.com/in/nialldouglas/



Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk