Doc. No.: WG21/N2528
J16/08-0038
Date: 2008-2-1
Reply to: Hans-J. Boehm
Phone: +1-650-857-3406
Email: Hans.Boehm@hp.com

N2528: Timed_mutex in C++0x

The current working paper in 30.3.2 defines a TimedMutex requirement and two implementations timed_mutex and timed_recursive_mutex. This was voted in, along with the threads API ( N2497), at the Kona meeting. Discussion in the review committee ( N2516) suggests that we should seriously consider removing this entire section, and reconsider it for TR2.

Why timed_mutex was in the proposal

Boost provides a timed_mutex class. Posix and Java provide a "lock with timeout" method on mutexes. (For Java, this is provided only for implementations of the java.util.concurrent.locks.Lock interface.) Thus there is some existing practice in the area. And the C++ threads API was modeled on Boost.

There appear to be some legitimate uses. A real-time system might use a fall-back algorithm if it cannot acquire a lock in a given amount of time. It's at least conceivable that one might want to run a deadlock detection algorithm if a mutex acquisition times out. Some uses of trylock may want to wait for a short period before giving up. (Though in many cases, it's used to avoid context switches, and this wouldn't make sense.)

Doug Lea described use cases for the Java facility (reproduced with permission):

My take on (Java) usage is that timeouts for locks are most often there to (1) help detect and deal with saturation (database locks not becoming free promptly etc), (2) for heuristically detecting or papering over deadlock-proneness (not as sleazy as it sounds), and (3) one ingredient for ensuring all-or-nothing deadline processing or meeting QoS.

None of these are "core" applications, but I don't like the thought of killing them completely and requiring hand-rolled solutions (which are not hard given timed condition waits, but also not trivial).

Note that none of the above usages are likely to require low-overhead highly scalable solutions, so letting them hit slower implementation paths should be fine.

Finally the implementation cost of timed_mutexes is very low. Howard Hinnant's prototype implementation uses a total of 76 lines.

Why timed_mutex turned out to be controversial

There are two possible implementation styles of timed_mutex-like functionality:
  1. Provide it as a separate class, as is done in the C++ working paper.
  2. Provide it as a member function on standard mutex types.
Both Java and Posix use the second approach. As Nick Stoughton pointed out, there is a strong argument for this: An interface may want to expose a lock to its clients. In that case, generally only the client will know whether it would like to acquire the lock with a timeout. However, with the first approach, it is the implementor of the interface who has to choose whether to use a timed_mutex. Thus abstractly, the second approach appears to be preferable.

However, as Howard Hinnant has pointed out, it would have been impractical for the C++ working paper to use the second approach. This would significantly slow down the standard mutex implementation on platforms that don't intrinsically provide this functionality. Although it may be acceptable to slow down timed mutex acquisitions, it is clearly not acceptable to slow down all mutex acquisitions in order to support a relatively infrequently used facility.

Since Posix provides pthread_mutex_timedlock only as part of a separate option, even some Posix platforms do not support it. It appears that a Windows implementation would have similar issues. Hence this slowdown for ordinary mutexes would be encountered on many platforms.

Thus the current interface appears to unavoidably diverge from Posix, another important ISO standard, and it appears to be less useful than Posix, though there is disagreement on how important this difference is.

Why we should postpone the controversy and discuss this only for TR2

Programmers are generally advised to avoid holding mutexes for long periods of time. Unlike condition variable waits, mutex acquisitions are expected to be fast. In the vast majority of cases, there is no reason to supply timeouts for mutex acquisitions.

A somewhat superficial examination of occurrences of the Boost and Posix facilities (using Google code search) showed up few uses (roughly 50 and 300 occurrences respectively, mostly in implementations and test suites). Clearly legitimate uses appeared infrequent.

Even if a timed_mutex is essential to a particular piece of code, it is still easy to reimplement, e.g. using the same 76 lines of code from Howard Hinnant's reference implementation. It is not at all clear that anyone incapable of reimplementing timed_mutex would be able to use it correctly either.

There is no evidence that this is a critical facility that needs to be in the initial version of the standard. Part of the reason for supporting it on other platforms appears to be to support real-time applications, which we do not support well at this stage in any case.

Postponing consideration may make our job easier in either of the following two cases:

  1. The existing facilities in Posix etc. remain largely unused. In that case, there is an argument that we should not supply it.
  2. The existing facilities become viewed as critical, and become universally available at the OS level. In that case, we may be able to use the more desirable member-function-based implementation, which is currently infeasible.
In either case, standardizing the existing timed_mutex facility would turn into a future liability.

Proposed resolution:

  1. Remove classes timed_mutex and recursive_timed_mutex from 30.3 synopsis.
  2. Delete 30.3.2.
  3. Remove timed_lock() members and timed constructor (absolute time and duration) from unique_lock in section 30.3.3.2.

Note: This has no impact on timed condition variable waits and hence the need to specify times and durations.