<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 986: Generic try_lock contradiction</title>
<meta property="og:title" content="Issue 986: Generic try_lock contradiction">
<meta property="og:description" content="C++ library issue. Status: C++11">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue986.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#C++11">C++11</a> status.</em></p>
<h3 id="986"><a href="lwg-defects.html#986">986</a>. Generic <code>try_lock</code> contradiction</h3>
<p><b>Section:</b> 32.6.6 <a href="https://wg21.link/thread.lock.algorithm">[thread.lock.algorithm]</a> <b>Status:</b> <a href="lwg-active.html#C++11">C++11</a>
 <b>Submitter:</b> Chris Fairles <b>Opened:</b> 2009-02-14 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all other</b> <a href="lwg-index.html#thread.lock.algorithm">issues</a> in [thread.lock.algorithm].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++11">C++11</a> status.</p>
<p><b>Discussion:</b></p>
<p>
In 32.6.6 <a href="https://wg21.link/thread.lock.algorithm">[thread.lock.algorithm]</a>, the generic <code>try_lock</code> effects (p2) say that a failed
<code>try_lock</code> is when it either returns <code>false</code> or throws an exception. In
the event a call to <code>try_lock</code> does fail, by either returning <code>false</code> or
throwing an exception, it states that <code>unlock</code> 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 <code>try_lock</code>?
</p>

<p>
Example:
</p>

<blockquote><pre>
#include &lt;mutex&gt;

int main() {
 std::mutex m0, m1, m2;
 std::unique_lock&lt;std::mutex&gt; l0(m0, std::defer_lock);
 std::unique_lock&lt;std::mutex&gt; l1(m1); //throws on try_lock
 std::unique_lock&lt;std::mutex&gt; 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() ); //??
}
</pre></blockquote>

<p>
The first lock's <code>try_lock</code> succeeded but, being a prior argument to a
lock whose <code>try_lock</code> failed, it gets unlocked as per the effects clause
of 32.6.6 <a href="https://wg21.link/thread.lock.algorithm">[thread.lock.algorithm]</a>. 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?
</p>

<p>
Further discussion and possible resolutions in c++std-lib-23049.
</p>

<p><i>[
Summit:
]</i></p>

<blockquote><p>
Move to review. Agree with proposed resolution.
</p></blockquote>

<p><i>[
Batavia (2009-05):
]</i></p>

<blockquote><p>
We agree with the proposed resolution.
Move to Tentatively Ready.
</p></blockquote>


<p id="res-986"><b>Proposed resolution:</b></p>

<p>
Change 32.6.6 <a href="https://wg21.link/thread.lock.algorithm">[thread.lock.algorithm]</a>, p2:
</p>

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

<p>
Delete the note from 32.6.6 <a href="https://wg21.link/thread.lock.algorithm">[thread.lock.algorithm]</a>, p3
</p>

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





</body>
</html>
