<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2288: Inconsistent requirements for shared mutexes</title>
<meta property="og:title" content="Issue 2288: Inconsistent requirements for shared mutexes">
<meta property="og:description" content="C++ library issue. Status: C++14">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2288.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++14">C++14</a> status.</em></p>
<h3 id="2288"><a href="lwg-defects.html#2288">2288</a>. Inconsistent requirements for shared mutexes</h3>
<p><b>Section:</b> 32.6.4.4 <a href="https://wg21.link/thread.sharedmutex.requirements">[thread.sharedmutex.requirements]</a> <b>Status:</b> <a href="lwg-active.html#C++14">C++14</a>
 <b>Submitter:</b> Daniel Kr&uuml;gler <b>Opened:</b> 2013-08-30 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++14">C++14</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Albeit shared mutex types refine timed mutex types, the requirements imposed on the corresponding required member function
expressions are inconsistent in several aspects, most probably because failing synchronisation with wording changes for
timed mutexes applied by some issues:
</p>

<ol>
<li>
<p>
Due to acceptance of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3568.html">N3568</a> a wording phrase
came in 32.6.4.4 <a href="https://wg21.link/thread.sharedmutex.requirements">[thread.sharedmutex.requirements]</a> p26,
</p>
<blockquote><p>
<i>Effects:</i> If the tick period of <code>rel_time</code> is not exactly convertible to the native tick period, the
duration shall be rounded up to the nearest native tick period. [&hellip;]
</p></blockquote>
<p> 
while a very similar one had been removed for 32.6.4.3 <a href="https://wg21.link/thread.timedmutex.requirements">[thread.timedmutex.requirements]</a> by LWG <a href="lwg-defects.html#2091" title="Misplaced effect in m.try_lock_for() (Status: C++14)">2091</a><sup><a href="https://cplusplus.github.io/LWG/issue2091" title="Latest snapshot">(i)</a></sup>. 
<p/>
Having this guaranteed effect for <code>try_lock_shared_for</code> but not for <code>try_lock_for</code> seems inconsistent
and astonishing.
<p/>
If the actual intended restriction imposed onto the implementation is to forbid early wakeups here, we should ensure that
to hold for timed mutex's <code>try_lock_for</code> as well. Note that the rationale provided for LWG <a href="lwg-defects.html#2091" title="Misplaced effect in m.try_lock_for() (Status: C++14)">2091</a><sup><a href="https://cplusplus.github.io/LWG/issue2091" title="Latest snapshot">(i)</a></sup> was
a potential late wakeup situation, but it seems that there is no implementation restriction that prevents early wakeups.
</p>
</li>

<li>
<p>
The shared-lock requirements for any <code>*lock*()</code> functions don't provide the guarantee that "If an exception is thrown then 
a lock shall not have been acquired for the current execution agent.". For other mutex types this guarantee can be derived from
the corresponding <code>TimedLockable</code> requirements, but there are no <code>SharedLockable</code> requirements.
</p>
</li>

<li>
<p>
The shared-lock requirements for <code>*lock_for/_until()</code> functions require "<i>Throws:</i> Nothing."
instead of "<i>Throws:</i> Timeout-related exceptions (30.2.4)." which had been added by LWG <a href="lwg-defects.html#2093" title="Throws clause of condition_variable::wait with predicate (Status: C++14)">2093</a><sup><a href="https://cplusplus.github.io/LWG/issue2093" title="Latest snapshot">(i)</a></sup>, because user-provided
clocks, durations, or time points may throw exceptions. 
</p>
</li>

<li>
<p>
With the addition of <code>std::shared_mutex</code>, the explicit lists of 32.6.4.2 <a href="https://wg21.link/thread.mutex.requirements.mutex">[thread.mutex.requirements.mutex]</a> p7+15,
</p>
<blockquote><p>
<i>Requires:</i> If <code>m</code> is of type <code>std::mutex</code> or <code>std::timed_mutex</code>, the calling thread does not own the mutex.
</p></blockquote>
<p>
and of 32.6.4.3 <a href="https://wg21.link/thread.timedmutex.requirements">[thread.timedmutex.requirements]</a> p4+11,
</p>
<blockquote><p>
<i>Requires:</i> If <code>m</code> is of type <code>std::timed_mutex</code>, the calling thread does not own the mutex.
</p></blockquote>
<p>
are incomplete and should add the non-recursive <code>std::shared_mutex</code> as well.
</p>
</li>
</ol>

<p><i>[2014-02-16: Moved as Immediate]</i></p>




<p id="res-2288"><b>Proposed resolution:</b></p>
<p>This wording is relative to N3691.</p>

<ol>
<li><p>Change 32.6.4.2 <a href="https://wg21.link/thread.mutex.requirements.mutex">[thread.mutex.requirements.mutex]</a> p7+15 as indicated:</p>

<blockquote>
<p>
-6- The expression <code>m.lock()</code> shall be well-formed and have the following semantics:
</p>
<blockquote>
<p>
-7- <i>Requires:</i> If <code>m</code> is of type <code>std::mutex</code><del> or</del><ins>,</ins> <code>std::timed_mutex</code><ins>, or 
<code>std::shared_mutex</code></ins>, the calling thread does not own the mutex.
</p>
</blockquote>
<p>
[&hellip;]
</p>
<p>
-14- The expression <code>m.try_lock()</code> shall be well-formed and have the following semantics:
</p>
<blockquote>
<p>
-15- <i>Requires:</i> If <code>m</code> is of type <code>std::mutex</code><del> or</del><ins>,</ins> <code>std::timed_mutex</code><ins>, or 
<code>std::shared_mutex</code></ins>, the calling thread does not own the mutex.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 32.6.4.3 <a href="https://wg21.link/thread.timedmutex.requirements">[thread.timedmutex.requirements]</a> p4+11 as indicated:</p>

<blockquote>
<p>
-3- The expression <code>m.try_lock_for(rel_time)</code> shall be well-formed and have the following semantics:
</p>
<blockquote>
<p>
-4- <i>Requires:</i> If <code>m</code> is of type <code>std::timed_mutex</code><ins> or <code>std::shared_mutex</code></ins>, 
the calling thread does not own the mutex.
</p>
</blockquote>
<p>
[&hellip;]
</p>
<p>
-10- The expression <code>m.try_lock_until(abs_time)</code> shall be well-formed and have the following semantics:
</p>
<blockquote>
<p>
-11- <i>Requires:</i> If <code>m</code> is of type <code>std::timed_mutex</code><ins> or <code>std::shared_mutex</code></ins>, 
the calling thread does not own the mutex.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 32.6.4.4 <a href="https://wg21.link/thread.sharedmutex.requirements">[thread.sharedmutex.requirements]</a> as indicated:</p>

<blockquote>
<p>
-3- The expression <code>m.lock_shared()</code> shall be well-formed and have the following semantics:
</p>
<blockquote>
<p>
-4- <i>Requires:</i> The calling thread has no ownership of the mutex.
<p/>
-5- <i>Effects:</i> Blocks the calling thread until shared ownership of the mutex can be obtained for the calling
thread. <ins>If an exception is thrown then a shared lock shall not have been acquired for the current thread.</ins>
<p/>
[&hellip;]
</p>
</blockquote>
<p>
-24- The expression <code>m.try_lock_shared_for(rel_time)</code> shall be well-formed and have the following semantics:
</p>
<blockquote>
<p>
-25- <i>Requires:</i> The calling thread has no ownership of the mutex.
<p/>
-26- <i>Effects:</i> <del>If the tick period of <code>rel_time</code> is not exactly convertible to the native tick period, the
duration shall be rounded up to the nearest native tick period.</del> Attempts to obtain shared lock
ownership for the calling thread within the relative timeout (30.2.4) specified by <code>rel_time</code>. If the
time specified by <code>rel_time</code> is less than or equal to <code>rel_time.zero()</code>, the function attempts to obtain
ownership without blocking (as if by calling <code>try_lock_shared()</code>). The function shall return within
the timeout specified by <code>rel_time</code> only if it has obtained shared ownership of the mutex object. [<i>Note:</i>
As with <code>try_lock()</code>, there is no guarantee that ownership will be obtained if the lock is available, but
implementations are expected to make a strong effort to do so. &mdash; <i>end note</i>] <ins>If an exception is thrown then 
a shared lock shall not have been acquired for the current thread.</ins>
<p/>
[&hellip;]
<p/>
-30- <i>Throws:</i> <del>Nothing</del><ins>Timeout-related exceptions (32.2.4 <a href="https://wg21.link/thread.req.timing">[thread.req.timing]</a>)</ins>.
</p>
</blockquote>
<p>
-31- The expression <code>m.try_lock_shared_until(abs_time)</code> shall be well-formed and have the following semantics:
</p>
<blockquote>
<p>
-32- <i>Requires:</i> The calling thread has no ownership of the mutex.
<p/>
-33- <i>Effects:</i> The function attempts to obtain shared ownership of the mutex. If <code>abs_time</code> has already
passed, the function attempts to obtain shared ownership without blocking (as if by calling <code>try_lock_shared()</code>). 
The function shall return before the absolute timeout (30.2.4) specified by <code>abs_time</code>
only if it has obtained shared ownership of the mutex object. [<i>Note:</i> As with <code>try_lock()</code>, there is no
guarantee that ownership will be obtained if the lock is available, but implementations are expected
to make a strong effort to do so. &mdash; <i>end note</i>] <ins>If an exception is thrown then 
a shared lock shall not have been acquired for the current thread.</ins>
<p/>
[&hellip;]
<p/>
-37- <i>Throws:</i> <del>Nothing</del><ins>Timeout-related exceptions (32.2.4 <a href="https://wg21.link/thread.req.timing">[thread.req.timing]</a>)</ins>.
</p>
</blockquote>
</blockquote>
</li>

</ol>





</body>
</html>
