<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 1507: promise::XXX_at_thread_exit functions have no
synchronization requirements</title>
<meta property="og:title" content="Issue 1507: promise::XXX_at_thread_exit functions have no
synchronization requirements">
<meta property="og:description" content="C++ library issue. Status: Resolved">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue1507.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#Resolved">Resolved</a> status.</em></p>
<h3 id="1507"><a href="lwg-defects.html#1507">1507</a>. <code>promise::<i>XXX</i>_at_thread_exit</code> functions have no
synchronization requirements</h3>
<p><b>Section:</b> 32.10.6 <a href="https://wg21.link/futures.promise">[futures.promise]</a> <b>Status:</b> <a href="lwg-active.html#Resolved">Resolved</a>
 <b>Submitter:</b> INCITS <b>Opened:</b> 2010-08-25 <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#futures.promise">issues</a> in [futures.promise].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#Resolved">Resolved</a> status.</p>
<p><b>Discussion:</b></p>
<p><b>Addresses US-199</b></p>
<p>
<code>promise::<i>XXX</i>_at_thread_exit</code> functions have no
synchronization requirements. Specifying synchronization
for these member functions requires coordinating with the
words in 32.10.6 <a href="https://wg21.link/futures.promise">[futures.promise]</a>/21 and 25, which give synchronization
requirements for <code>promise::set_value</code> and
<code>promise::set_exception</code> (32.10.6 <a href="https://wg21.link/futures.promise">[futures.promise]</a> p. 26 ff., p. 29 ff.).
</p>
<p><i>[
Resolution proposed by ballot comment:
]</i></p>

<blockquote><p>
Change 32.10.6 <a href="https://wg21.link/futures.promise">[futures.promise]</a>/21 to mention <code>set_value_at_thread_exit</code> and
<code>set_exception_at_thread_exit;</code> with this text, replace 32.10.6 <a href="https://wg21.link/futures.promise">[futures.promise]</a>/25 
and add two new paragraphs, after 32.10.6 <a href="https://wg21.link/futures.promise">[futures.promise]</a>/28 and 32.10.6 <a href="https://wg21.link/futures.promise">[futures.promise]</a>/31.
</p></blockquote>

<p><i>[2011-03-8: Lawrence comments and drafts wording]</i></p>


<p>This comment applies as well to other <code>*_at_thread_exit</code>
functions.  The following resolution adds synchronization paragraphs
to all of them and edits a couple of related synchronization
paragraphs.</p>

<p><i>[2011-03-09: Hans and Anthony add some improvements]</i></p>


<p><i>[2011-03-19: Detlef comments]</i></p>


<p>In regard to the suggested part:</p>

<blockquote><p>
These operations do not provide any ordering guarantees with
respect to other operations, except through operations on futures
that reference the same shared state.
</p></blockquote>

<p>I would like this to change to:</p>

<blockquote><p>
These operations do not provide any ordering guarantees with
respect to other operations on the same promise object.
[<i>Note</i>: They synchronize with calls to operations on
objects that refer to the same shared state according to
32.10.5 <a href="https://wg21.link/futures.state">[futures.state]</a>. &mdash; <i>end note</i>]
</p></blockquote>

<p>The current proposed resolution has exactly the same paragraph at
for places. I propose to have it only once as new paragraph 2.</p>

<p>This also covers <a href="lwg-defects.html#1504" title="Term &quot;are serialized&quot; is not defined (Status: Resolved)">1504</a><sup><a href="https://cplusplus.github.io/LWG/issue1504" title="Latest snapshot">(i)</a></sup> (US-196) and <a href="lwg-defects.html#1505" title="Synchronization between promise::set_value and future::get (Status: Resolved)">1505</a><sup><a href="https://cplusplus.github.io/LWG/issue1505" title="Latest snapshot">(i)</a></sup> (US-197).
US-197 is essentially rejected with this resolution, but a clarification is added 
that the normative wording is already in 32.10.5 <a href="https://wg21.link/futures.state">[futures.state]</a>.</p>

<blockquote class="note">
<p>Proposed Resolution</p>
<ol>
<li><p>Edit 32.6.4.2 <a href="https://wg21.link/thread.mutex.requirements.mutex">[thread.mutex.requirements.mutex]</a> paragraph 5 as follows:</p>

<blockquote><p>
5 The implementation shall provide lock and unlock operations, as described below. <del>The implementation 
shall serialize those operations.</del><ins>For purposes of determining the existence of a data race, these
behave as atomic operations (6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>).  The lock and unlock operations on
a single mutex shall appear to occur in a single total order. [<i>Note</i>: this can be viewed as the 
modification order (6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) of the mutex. &mdash; <i>end note</i>]</ins> [ <i>Note</i>: 
Construction and destruction of an object of a mutex type need not be thread-safe; other synchronization 
should be used to ensure that mutex objects are initialized and visible to other threads. &mdash; <i>end note</i> ]
</p></blockquote>
</li>

<li><p>Edit 32.7 <a href="https://wg21.link/thread.condition">[thread.condition]</a> paragraphs 6-9 as follows:</p>

<blockquote><pre>
void notify_all_at_thread_exit(condition_variable&amp; cond, unique_lock&lt;mutex&gt; lk);
</pre>
<blockquote>
<p>
-6- <i>Requires</i>: <code>lk</code> is locked by the calling thread and either
</p>
<ul>
<li>no other thread is waiting on <code>cond</code>, or</li>
<li><code>lk.mutex()</code> returns the same value for each of the lock arguments supplied by all concurrently
waiting (via <code>wait</code>, <code>wait_for</code>, or <code>wait_until</code>) threads.</li>
</ul>
<p>
-7- <i>Effects</i>: transfers ownership of the lock associated with <code>lk</code> into internal storage and schedules 
<code>cond</code> to be notified when the current thread exits, after all objects of thread storage duration 
associated with the current thread have been destroyed. This notification shall be as if
</p>
<blockquote><pre>
lk.unlock();
cond.notify_all();
</pre></blockquote>
<p>
<ins>-?- <i>Synchronization:</i> The call to <code>notify_all_at_thread_exit</code>
and the completion of the destructors for all the current thread's variables of 
thread storage duration synchronize with (6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) calls 
to functions waiting on <code>cond</code>.</ins>
<p/>
-8- <i>Note</i>: The supplied lock will be held until the thread exits, and care must be taken to ensure that
this does not cause deadlock due to lock ordering issues. After calling <code>notify_all_at_thread_exit</code>
it is recommended that the thread should be exited as soon as possible, and that no blocking or
time-consuming tasks are run on that thread.
<p/>
-9- <i>Note</i>: It is the user's responsibility to ensure that waiting threads do not erroneously 
assume that the thread has finished if they experience spurious wakeups. This typically requires 
that the condition being waited for is satisfied while holding the lock on <code>lk</code>, and that 
this lock is not released and reacquired prior to calling <code>notify_all_at_thread_exit</code>.
</p>
</blockquote></blockquote>
</li>

<li><p>Edit 32.10.6 <a href="https://wg21.link/futures.promise">[futures.promise]</a>, paragraphs 14-27 as follows:</p>

<blockquote><pre>
void promise::set_value(const R&amp; r);
void promise::set_value(R&amp;&amp; r);
void promise&lt;R&amp;&gt;::set_value(R&amp; r);
void promise&lt;void&gt;::set_value();
</pre>
<blockquote>
<p>
-14- <i>Effects</i>: atomically stores the value <code>r</code> in the shared state and makes that state 
ready (32.10.5 <a href="https://wg21.link/futures.state">[futures.state]</a>).
<p/>
-15- <i>Throws</i>:
</p>
<ul>
<li><code>future_error</code> if its shared state already has a stored value or exception, or</li>
<li>for the first version, any exception thrown by the copy constructor of <code>R</code>, or</li>
<li>for the second version, any exception thrown by the move constructor of <code>R</code>.</li>
</ul>
<p>
-16- <i>Error conditions</i>:
</p>
<ul>
<li><code>promise_already_satisfied</code> if its shared state already has a stored value or exception.</li>
<li><code>no_state</code> if <code>*this</code> has no shared state.</li>
</ul>
<p>
-17- <i>Synchronization</i>: <del>calls to <code>set_value</code> and <code>set_exception</code> on a single 
<code>promise</code> object are serialized. [ <i>Note</i>: And they synchronize and serialize with other functions 
through the referred shared state. &mdash; <i>end note</i> ]</del><ins>For purposes of determining the 
existence of a data race, <code>set_value</code>, <code>set_exception</code>, <code>set_value_at_thread_exit</code>,
and <code>set_exception_at_thread_exit</code> behave as atomic operations (6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) on
the memory location associated with the <code>promise</code>. Calls to these operations on a single promise shall 
appear to occur in a single total order.  [<i>Note</i>: this can be viewed as the modification order
(6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) of the promise. &mdash; <i>end note</i>] These operations do not 
provide any ordering guarantees with respect to other operations, except through operations on futures
that reference the same shared state.</ins>
</p>
</blockquote></blockquote>

<blockquote><pre>
void set_exception(exception_ptr p);
</pre>
<blockquote>
<p>
-18- <i>Effects</i>: atomically stores the exception pointer <code>p</code> in the shared state and makes that 
state ready (32.10.5 <a href="https://wg21.link/futures.state">[futures.state]</a>).
</p>

<p>
-19- <i>Throws</i>: <code>future_error</code> if its shared state already has a stored value or exception.
</p>

<p>
-20- <i>Error conditions</i>:
</p>
<ul>
<li><code>promise_already_satisfied</code> if its shared state already has a stored value or exception.</li>
<li><code>no_state</code> if <code>*this</code> has no shared state.</li>
</ul>

<p>
-21- <i>Synchronization</i>: <del>calls to <code>set_value</code> and <code>set_exception</code> on a single 
<code>promise</code> object are serialized. [ <i>Note</i>: And they synchronize and serialize with 
other functions through the referred shared state. &mdash; <i>end note</i> ]</del><ins>For purposes of determining the 
existence of a data race, <code>set_value</code>, <code>set_exception</code>, <code>set_value_at_thread_exit</code>,
and <code>set_exception_at_thread_exit</code> behave as atomic operations (6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) on
the memory location associated with the <code>promise</code>. Calls to these operations on a single promise shall 
appear to occur in a single total order.  [<i>Note</i>: this can be viewed as the modification order
(6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) of the promise. &mdash; <i>end note</i>] These operations do not 
provide any ordering guarantees with respect to other operations, except through operations on futures
that reference the same shared state.</ins>
</p>
</blockquote></blockquote>

<blockquote><pre>
void promise::set_value_at_thread_exit(const R&amp; r);
void promise::set_value_at_thread_exit(R&amp;&amp; r);
void promise&lt;R&amp;&gt;::set_value_at_thread_exit(R&amp; r);
void promise&lt;void&gt;::set_value_at_thread_exit();
</pre>
<blockquote>
<p>
-22- <i>Effects</i>: Stores the value <code>r</code> in the shared state without making that state 
ready immediately. Schedules that state to be made ready when the current thread exits, after 
all objects of thread storage duration associated with the current thread have been destroyed.
<p/>
-23- <i>Throws</i>: <code>future_error</code> if an error condition occurs.
<p/>
-24- <i>Error conditions</i>:
</p>
<ul>
<li><code>promise_already_satisfied</code> if its shared state already has a stored value or exception.</li>
<li><code>no_state</code> if <code>*this</code> has no shared state.</li>
</ul>
<p>
<ins>-??- <i>Synchronization</i>: For purposes of determining the existence of a data race, <code>set_value</code>, 
<code>set_exception</code>, <code>set_value_at_thread_exit</code>, and <code>set_exception_at_thread_exit</code> behave as 
atomic operations (6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) on the memory location associated with the <code>promise</code>. 
Calls to these operations on a single promise shall appear to occur in a single total order.  [<i>Note</i>: 
this can be viewed as the modification order (6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) of the promise. &mdash; 
<i>end note</i>] These operations do not provide any ordering guarantees with respect to other operations, 
except through operations on futures that reference the same shared state.</ins>
</p>
</blockquote></blockquote>

<blockquote><pre>
void promise::set_exception_at_thread_exit(exception_ptr p);
</pre>
<blockquote>
<p>
-25- <i>Effects</i>: Stores the exception pointer <code>p</code> in the shared state without 
making that state ready immediately. Schedules that state to be made ready when the current 
thread exits, after all objects of thread storage duration associated with the current 
thread have been destroyed.
<p/>
-26- <i>Throws</i>: <code>future_error</code> if an error condition occurs.
<p/>
-27- <i>Error conditions</i>:
</p>
<ul>
<li><code>promise_already_satisfied</code> if its shared state already has a stored value or exception.</li>
<li><code>no_state</code> if <code>*this</code> has no shared state.</li>
</ul>
<p>
<ins>-??- <i>Synchronization</i>: For purposes of determining the existence of a data race, <code>set_value</code>, 
<code>set_exception</code>, <code>set_value_at_thread_exit</code>, and <code>set_exception_at_thread_exit</code> behave as 
atomic operations (6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) on the memory location associated with the <code>promise</code>. 
Calls to these operations on a single promise shall appear to occur in a single total order.  [<i>Note</i>: 
this can be viewed as the modification order (6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) of the promise. &mdash; 
<i>end note</i>] These operations do not provide any ordering guarantees with respect to other operations, 
except through operations on futures that reference the same shared state.</ins>
</p>
</blockquote></blockquote>
</li>

<li><p>Edit 32.10.10.2 <a href="https://wg21.link/futures.task.members">[futures.task.members]</a>, paragraph 15-21 as follows:</p>

<blockquote><pre>
void operator()(ArgTypes... args);
</pre>
<blockquote>
<p>
-15- <i>Effects</i>: <code><var>INVOKE</var>(f, t1, t2, ..., tN, R)</code>, where <code>f</code> is the stored task 
of <code>*this</code> and <code>t1</code>, <code>t2</code>, <code>...</code>, <code>tN</code> are the values in 
<code>args...</code>. If the task returns normally, the return value is stored as the asynchronous 
result in the shared state of <code>*this</code>, otherwise the exception thrown by the task is 
stored. The shared state of <code>*this</code> is made ready, and any threads blocked in a function 
waiting for the shared state of <code>*this</code> to become ready are unblocked.
<p/>
-16- <i>Throws</i>: a <code>future_error</code> exception object if there is no shared state or the stored 
task has already been invoked.
<p/>
-17- <i>Error conditions</i>:
</p>
<ul>
<li><code>promise_already_satisfied</code> if the shared state is already ready.</li>
<li><code>no_state</code> if <code>*this</code> has no shared state.</li>
</ul>
<p>
-18- <i>Synchronization</i>: a successful call to <code>operator()</code> synchronizes with (6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) 
a call to any member function of a <code>future</code> or <code>shared_future</code> object that shares the 
shared state of <code>*this</code>. The completion of the invocation of the stored task and the storage 
of the result (whether normal or exceptional) into the shared state synchronizes with (6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) 
the successful return from any member function that detects that the state is set to ready. [ <i>Note</i>: 
<code>operator()</code> synchronizes and serializes with other functions through the shared state. &mdash; <i>end note</i> ]
</p>
</blockquote></blockquote>

<blockquote><pre>
void make_ready_at_thread_exit(ArgTypes... args);
</pre>
<blockquote>
<p>
-19- <i>Effects</i>: <code><var>INVOKE</var>(f, t1, t2, ..., tN, R)</code>, where <code>f</code> is the 
stored task and <code>t1</code>, <code>t2</code>, <code>...</code>, <code>tN</code> are the values in <code>args...</code>. 
If the task returns normally, the return value is stored as the asynchronous result in the shared 
state of <code>*this</code>, otherwise the exception thrown by the task is stored. In either case, 
this shall be done without making that state ready (32.10.5 <a href="https://wg21.link/futures.state">[futures.state]</a>) immediately. 
Schedules the shared state to be made ready when the current thread exits, after all objects of 
thread storage duration associated with the current thread have been destroyed.
<p/>
-20- <i>Throws</i>: <code>future_error</code> if an error condition occurs.
<p/>
-21- <i>Error conditions</i>:
</p>
<ul>
<li><code>promise_already_satisfied</code> if the shared state already has a stored value or exception.</li>
<li><code>no_state</code> if <code>*this</code> has no shared state.</li>
</ul>
<p>
<ins>-??- <i>Synchronization:</i> a successful call to <code>make_ready_at_thread_exit</code>
synchronizes with (6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) a call to any member function of
a <code>future</code> or <code>shared_future</code> object that shares the shared state of 
<code>*this</code>. The completion of</ins>
</p>
<ul>
<li><p><ins>the invocation of the stored task and the storage of the result (whether normal or 
exceptional) into the shared state</ins></p></li>
<li><p><ins>the destructors for all the current thread's variables of thread storage duration</ins></p></li>
</ul>
<p>
<ins>synchronize with (6.10.2 <a href="https://wg21.link/intro.multithread">[intro.multithread]</a>) the successful return from any member function
that detects that the state is set to ready. [<i>Note:</i> <code>make_ready_at_thread_exit</code>
synchronizes and serializes with other functions through the shared state. &mdash; <i>end note</i>]</ins>
</p>
</blockquote></blockquote>

</li>
</ol>
</blockquote>


<p id="res-1507"><b>Proposed resolution:</b></p><p>
Resolved 2011-03 Madrid meeting by paper <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3278">N3278</a>
</p>




</body>
</html>
