This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++11 status.

### 1497. `lock()` postcondition can not be generally achieved

Section: 33.7 [thread.condition] Status: C++11 Submitter: Switzerland Opened: 2010-08-25 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [thread.condition].

View all issues with C++11 status.

Discussion:

Addresses CH-30

If `lock.lock()` throws an exception, the postcondition can not be generally achieved.

[ Resolution proposed by ballot comment: ]

> Either state that the postcondition might not be achieved, depending on the error condition, or state that `terminate()` is called in this case.

[ 2010-08-13 Peter Sommerlad comments and provides wording ]

> 33.7.4 [thread.condition.condvar], 33.7.5 [thread.condition.condvarany]

> p. 13, last bullet, and corresponding paragraphs in all wait functions

> Problem:
> Condition variable wait might fail, because the lock cannot be acquired when notified. CH-30 says: "If lock.lock() throws an exception, the postcondition can not be generally achieved." CH-30 proposes: "Either state that the postcondition might not be achieved, depending on the error condition, or state that terminate() is called in this case."

> The discussion in Rapperswil concluded that calling `terminate()` might be too drastic in this case and a corresponding exception should be thrown/passed on and one should use a lock type that allows querying its status, which `unique_lock` allows for `std::condition_variable`

> We also had some additional observations while discussing in Rapperswil:
> - in 33.7.4 [thread.condition.condvar] `wait` with predicate and `wait_until` with predicate lack the precondition, postcondition and Error conditions sections. the lack of the precondition would allow to call `pred()` without holding the lock.
> - in 33.7.4 [thread.condition.condvar] `wait_until` and `wait_for` and 33.7.5 [thread.condition.condvarany] `wait_for` still specify an error condition for a violated precondition. This should be removed.

> and add the following proposed solution:

[2011-02-27: Daniel adapts numbering to n3225]

Proposed resolution:

1. Change 33.7.4 [thread.condition.condvar] as indicated:

   >     void wait(unique_lock<mutex>& lock);

   > 9 Requires: `lock``.owns_lock()` is `true` and `lock.mutex()` is locked by the calling thread, and either

   > - no other thread is waiting on this `condition_variable` object or
   > - `lock.mutex()` returns the same value for each of the `lock` arguments supplied by all concurrently waiting (via `wait` or `timed_wait`) threads.

   [..]

   > 11 Postcondition: `lock``.owns_lock()` is `true` and `lock.mutex()` is locked by the calling thread.

   [..]

   >     template <class Predicate>
   >     void wait(unique_lock<mutex>& lock, Predicate pred);

   > ?? Requires: `lock.owns_lock()` is `true` and `lock.mutex()` is locked by the calling thread, and either

   > - no other thread is waiting on this `condition_variable` object or
   > - `lock.mutex()` returns the same value for each of the `lock` arguments supplied by all concurrently waiting (via `wait` or `timed_wait`) threads.

   > 14 Effects:

   > >     while (!pred())
   > >       wait(lock);

   > ?? Postcondition: `lock.owns_lock()` is `true` and `lock.mutex()` is locked by the calling thread.

   > ?? Throws: `std::system_error` when an exception is required (30.2.2).

   > ?? Error conditions:

   > - equivalent error condition from `lock.lock()` or `lock.unlock()`.

   >     template <class Clock, class Duration>
   >     cv_status wait_until(unique_lock<mutex>& lock,
   >       const chrono::time_point<Clock, Duration>& abs_time);

   > 15 Requires: `lock``.owns_lock()` is `true` and `lock.mutex()` is locked by the calling thread, and either

   > - no other thread is waiting on this `condition_variable` object or
   > - `lock.mutex()` returns the same value for each of the `lock` arguments supplied by all concurrently waiting (via `wait`, `wait_for`, or `wait_until`) threads.

   [..]

   > 17 Postcondition: `lock``.owns_lock()` is `true` and `lock.mutex()` is locked by the calling thread.

   [..]

   > 20 Error conditions:

   > - `operation_not_permitted` — if the thread does not own the lock.
   > - equivalent error condition from `lock.lock()` or `lock.unlock()`.

   >     template <class Rep, class Period>
   >     cv_status wait_for(unique_lock<mutex>& lock,
   >       const chrono::duration<Rep, Period>& rel_time);

   > 21 Requires: `lock``.owns_lock()` is `true` and `lock.mutex()` is locked by the calling thread, and either

   > - no other thread is waiting on this `condition_variable` object or
   > - `lock.mutex()` returns the same value for each of the `lock` arguments supplied by all concurrently waiting (via `wait`, `wait_for`, or `wait_until`) threads.

   [..]

   > 24 Postcondition: `lock``.owns_lock()` is `true` and `lock.mutex()` is locked by the calling thread.

   [..]

   > 26 Error conditions:

   > - `operation_not_permitted` — if the thread does not own the lock.
   > - equivalent error condition from `lock.lock()` or `lock.unlock()`.

   >     template <class Clock, class Duration, class Predicate>
   >     bool wait_until(unique_lock<mutex>& lock,
   >       const chrono::time_point<Clock, Duration>& abs_time,
   >         Predicate pred);

   > ?? Requires: `lock.owns_lock()` is `true` and `lock.mutex()` is locked by the calling thread, and either

   > - no other thread is waiting on this `condition_variable` object or
   > - `lock.mutex()` returns the same value for each of the `lock` arguments supplied by all concurrently waiting (via `wait` or `timed_wait`) threads.

   > 27 Effects:

   > >     while (!pred())
   > >       if (wait_until(lock, abs_time) == cv_status::timeout)
   > >         return pred();
   > >     return true;

   > 28 Returns: `pred()`

   > ?? Postcondition: `lock.owns_lock()` is `true` and `lock.mutex()` is locked by the calling thread.

   > 29 [ Note: The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered. — end note ]

   > ?? Throws: `std::system_error` when an exception is required (30.2.2).

   > ?? Error conditions:

   > - equivalent error condition from `lock.lock()` or `lock.unlock()`.

   >     template <class Rep, class Period, class Predicate>
   >     bool wait_for(unique_lock<mutex>& lock,
   >       const chrono::duration<Rep, Period>& rel_time,
   >         Predicate pred);

   > 30 Requires: `lock``.owns_lock()` is `true` and `lock.mutex()` is locked by the calling thread, and either

   > - no other thread is waiting on this `condition_variable` object or
   > - `lock.mutex()` returns the same value for each of the `lock` arguments supplied by all concurrently waiting (via `wait`, `wait_for`, or `wait_until`) threads.

   [..]

   > 33 Postcondition: `lock``.owns_lock()` is `true` and `lock.mutex()` is locked by the calling thread.

   [..]

   > 37 Error conditions:

   > - `operation_not_permitted` — if the thread does not own the lock.
   > - equivalent error condition from `lock.lock()` or `lock.unlock()`.

2. Change 33.7.5 [thread.condition.condvarany] as indicated:

   [..]

   >     template <class Lock, class Predicate>
   >     void wait(Lock& lock, Predicate pred);

   > [Note: if any of the wait functions exits with an exception it is indeterminate if the `Lock` is held. One can use a `Lock` type that allows to query that, such as the `unique_lock` wrapper. — end note]

   > 11 Effects:

   > >     while (!pred())
   > >       wait(lock);

   [..]

   > 31 Error conditions:

   > - `operation_not_permitted` — if the thread does not own the lock.
   > - equivalent error condition from `lock.lock()` or `lock.unlock()`.