On Thursday 30 August 2018 at 21:10:48 +0100, Mike Crowe wrote:
> C++11's std::condition_variable, std::timed_mutex and
> std::recursive_timed_mutex support waiting with a timeout specified using
> an arbitrary clock. It's common to use std::chrono::steady_clock (which
> corresponds to CLOCK_MONOTONIC) or std::chrono::system_clock (which
> corresponds to CLOCK_REALTIME) for these waits, and other clocks end up
> being converted to one of those when performing the wait.
> 
> Unfortunately, I don't believe that it's possible to implement these on top
> of the pthread equivalents correctly for std::chrono::steady_clock (i.e.
> CLOCK_MONOTONIC) since:
> 
> 1. pthread_mutex_timedlock only supports a time measured against
>    CLOCK_REALTIME.
> 
> 2. The clock used for pthread_cond_timedwait must be specified when the
>    condition variable is created by pthread_cond_init. The clock to be used
>    for future waits is not known at the point that the
>    std::condition_variable constructor is called.
> 
> I'm most interested in the std::condition_variable case. since I have code
> that wants to wait using std::chrono::steady_clock.
> 
> There are a number of possible workarounds for these. I've described some
> in a blog post[1] and in defect 0001164[2]. But, my favourite solution is
> to introduce a variant of pthread_cond_timedwait that takes a an additional
> clockid_t parameter:
> 
>  int pthread_cond_timedwaitonclock(pthread_cond_t *cond,
>                                    pthread_mutex_t *mutex,
>                                    clockid_t clockid,
>                                    const struct timespec *abstimeout);
> 
> I've proposed[3] an implementation of this function for glibc (as
> pthread_cond_timedwaitonclock_np) and it was suggested that I ought to
> raise it here. (This led me to enter defect 0001164, but since that yielded
> no response I've finally got round to writing this email too.)
> 
> The equivalent for mutex would probably be:
> 
>  int pthread_mutex_timedlockonclock(pthread_mutex_t *mutex,
>                                     clockid_t clockid,
>                                     const struct timespec *abstimeout);
> 
> but I've not yet made any attempt to implement it in glibc.
> 
> Would making the C++ standard library implementable on top of POSIX be
> considered a good enough reason to add such functions?
> 
> Are these functions generic enough or perhaps too generic? Android had a
> pthread_cond_timedwait_monotonic function for a while, but deprecated it
> when they added support for pthread_condattr_setclock.
> 
> Thanks.
> 
> Mike.
> 
> [1] 
> https://randombitsofuselessinformation.blogspot.com/2018/06/its-about-time-monotonic-time.html
> [2] http://austingroupbugs.net/view.php?id=1164
> [3] 
> http://libc-alpha.sourceware.narkive.com/3ZPZzEOy/rfcv4-add-pthread-cond-timedwaitonclock-np#post1

I received one direct reply to this email from someone who wasn't sure if
their response was worth of the list. I thought it was. I understood their
main points to be:

> The library code now has to track the clock for each invocation of
> pthread_cond_timedwaitonclock and not (once) per condition variable.

Only if the underlying implementation expects that.

At least in the glibc implementation I've been working with, the clock to
use is a parameter to the underlying operating system futex wait operation.
Supplying it at construction time means that the clock must be stored
within the condition variable and retrieved when the wait operation is
called. I have implemented pthread_cond_timedwait in terms of
pthread_cond_timedwaitonclock.

> The situations where a single condition variable (or mutex) has waiting
> threads that use different clocks would seem to be very rare;

I agree, but the clock to use is a property of the wait and not a property
of the condition variable so it makes more sense (and it is easier to
reason about the code locally) if the clock is supplied in the call rather
than at construction. In C++ the clock is part of the type of the parameter
passed to the wait operation so it can be automatically inferred.

> An application as a whole is interested in real time or in clock
> monotonic time.

I don't believe that's true, especially when code is hidden away in
libraries. A calendar application may wish to use CLOCK_REALTIME for events
but CLOCK_MONOTONIC for notification timeouts.

> pthread_mutex_timedlockonclock can be implemented using a condition
> variable configured to use an appropriate clock.

It can be, if pthread_cond_timedwaitonclock is available, otherwise you're
back to not knowing the clock at construction time. I'm sceptical that
adding the overhead of a condition variable for every std::timed_mutex
instance will be acceptable to C++ standard library authors.

> Non-monotonic changes to CLOCK_REALTIME should be rare since methods
> exist to correct a slightly-wrong clock without it going backwards.

Systems, particularly embedded ones, may boot without knowing the current
time and only set the system clock later. This may be quite a long time
later if they don't immediately have an Internet connection. A desktop user
may notice that their clock is completely wrong and take action to correct
it.

I know of several systems that have had real bugs due to using
CLOCK_REALTIME when they meant CLOCK_MONOTONIC. There has been a trend
among many Linux system libraries over the last few years away from using
CLOCK_REALTIME (often just via time(2) or gettimeofday(2)) towards using
CLOCK_MONOTONIC instead.

Thanks.

Mike.

Reply via email to