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.

### 986. Generic `try_lock` contradiction

Section: 32.5.6 [thread.lock.algorithm] Status: C++11 Submitter: Chris Fairles Opened: 2009-02-14 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [thread.lock.algorithm].

View all issues with C++11 status.

Discussion:

In 32.5.6 [thread.lock.algorithm], the generic `try_lock` effects (p2) say that a failed `try_lock` is when it either returns `false` or throws an exception. In the event a call to `try_lock` does fail, by either returning `false` or throwing an exception, it states that `unlock` shall be called for all prior arguments. Then the returns clause (p3) goes on to state in a note that after returning, either all locks are locked or none will be. So what happens if multiple locks fail on `try_lock`?

Example:

>     #include <mutex>

>     int main() {
>      std::mutex m0, m1, m2;
>      std::unique_lock<std::mutex> l0(m0, std::defer_lock);
>      std::unique_lock<std::mutex> l1(m1); //throws on try_lock
>      std::unique_lock<std::mutex> l2(m2); //throws on try_lock

>      int result = std::try_lock(l0, l1, l2);

>      assert( !l0.owns_lock() );
>      assert( l1.owns_lock() ); //??
>      assert( l2.owns_lock() ); //??
>     }

The first lock's `try_lock` succeeded but, being a prior argument to a lock whose `try_lock` failed, it gets unlocked as per the effects clause of 32.5.6 [thread.lock.algorithm]. However, 2 locks remain locked in this case but the return clause states that either all arguments shall be locked or none will be. This seems to be a contradiction unless the intent is for implementations to make an effort to unlock not only prior arguments, but the one that failed and those that come after as well. Shouldn't the note only apply to the arguments that were successfully locked?

Further discussion and possible resolutions in c++std-lib-23049.

[ Summit: ]

> Move to review. Agree with proposed resolution.

[ Batavia (2009-05): ]

> We agree with the proposed resolution. Move to Tentatively Ready.

Proposed resolution:

Change 32.5.6 [thread.lock.algorithm], p2:

> -2- Effects: Calls `try_lock()` for each argument in order beginning with the first until all arguments have been processed or a call to `try_lock()` fails, either by returning `false` or by throwing an exception. If a call to `try_lock()` fails, `unlock()` shall be called for all prior arguments and there shall be no further calls to `try_lock()`.

Delete the note from 32.5.6 [thread.lock.algorithm], p3

> -3- Returns: -1 if all calls to `try_lock()` returned `true`, otherwise a 0-based index value that indicates the argument for which `try_lock()` returned `false`. [Note: On return, either all arguments will be locked or none will be locked. -- end note]