<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <title>N3267 - A review of noexcept in the threads library</title>
  <style type="text/css">
    p {text-align:justify}
    li {text-align:justify}
    ins {background-color:#A0FFA0}
    del {background-color:#FF6666}
    
    tr.TITLE_ROW {text-align: center; font-weight: bold}
    tr.DELETED {background: #FF6666; text-decoration: line-through}
    tr.INSERTED {background: #FFFF99}
  </style>
</head>
<body>
<address>Document number: N3267=11-0037<br>
Date: 2011-03-23<br>
J. Daniel Garcia, Michael Wong<br>
Project: Programming Language C++, Library Working Group<br>
Reply To: <a href="mailto:josedaniel.garcia@uc3m.es">josedaniel.garcia@uc3m.es</a>
</address>
<hr>
<h1>N3267 - A review of noexcept in the threads library (revised)</h1>
<p>This paper studies possible changes to the Threads Library to make
broad use of noexcept. The paper addresses National Body comments CH 16
and GB 60. It is a revision of&nbsp; N3252 in the mailing based on
discussions in Madrid, after the update of new criteria&nbsp; for
noexcept.<br>
</p>
<p>
Changes in this paper are <b>restricted to chapter 30</b> (threads
library).
</p>
<p>
All changes in this paper are relative to N3242.
</p>
<h2>Discussion</h2>
<p>Several <tt>swap()</tt> functions have been made <tt>noexcept</tt>
as they are defined in terms of the corresponding <tt>noexcept</tt>
member function.</p>
<p>In 30.4.1 <tt>mutex</tt>, <tt>recursive_mutex</tt>, <tt>timed_mutex</tt>
and <tt>recursive_timed_mutex</tt> constructors have been made <tt>noexcept</tt>
In section 30.6.1 some operations have been made <tt>noexcept</tt> to
be consistent with the disgnostics library.
In section 30.6.10 member function <tt>valid</tt> is not consistent
with its definition in 30.6.10.1. It has been updated.
In general all the swap member functions have been revised regarding to
its <i>noexcept</i> specification.
Member function <tt>unlock()</tt> has lost its <i>noexcept</i>
specification because it has a precondition.
</p>
<h2>Acknowledgments</h2>
The following people provided very useful comments to improve this
paper: Jonathan Wakely, Daniel Krügler, Alisdair
Meredith, and the rest of the Concurrent subgroup.
<h1>Proposed Wording</h1>
<h2>30.3 Threads [thread.threads]</h2>
After p. 1
<pre>namespace std {<br>  #define __STDCPP_THREADS__ __cplusplus<br><br>  class thread;<br><br>  void swap(thread&amp; x, thread&amp; y)<ins> noexcept</ins>;<br><br>  namespace this_thread {<br>    thread::id get_id()<ins> noexcept</ins>;<br>    void yield()<ins> noexcept</ins>;<br>    template &lt;class Clock, class Duration&gt;<br>      void sleep_until(const chrono::time_point&lt;Clock, Duration&gt;&amp; abs_time);<br>  template &lt;class Rep, class Period&gt;<br>    void sleep_for(const chrono::duration&lt;Rep, Period&gt;&amp; rel_time);<br>  }<br>}<br></pre>
<h2>30.3.2 Namespace this_thread [thread.thread.this]</h2>
Before p. 1
<pre>namespace std {<br>  namespace this_thread {<br>    thread::id get_id() noexcept;<br>    void yield() noexcept;<br>    template &lt;class Clock, class Duration&gt;<br>      void sleep_until(const chrono::time_point&lt;Clock, Duration&gt;&amp; abs_time)<del> noexcept</del>;<br>    template &lt;class Rep, class Period&gt;<br>      void sleep_for(const chrono::duration&lt;Rep, Period&gt;&amp; rel_time)<del> noexcept</del>;<br>  }<br>}<br></pre>
After p. 3
<pre>template &lt;class Clock, class Duration&gt;<br>  void sleep_until(const chrono::time_point&lt;Clock, Duration&gt;&amp; abs_time)<del> noexcept</del>;<br></pre>
After p. 5
<pre>template &lt;class Rep, class Period&gt;<br>  void sleep_for(const chrono::duration&lt;Rep, Period&gt;&amp; rel_time)<del> noexcept</del>;<br></pre>
<h2>30.3.1.7 thread specialized algorithms [thread.thread.algorithm]</h2>
Before p.1
<pre>void swap(thread&amp; x, thread&amp; y)<ins> noexcept</ins>;</pre>
<h2>30.4 Mutual exclusion [thread.mutex]</h2>
After p. 1
<pre>namespace std {<br>...<br>  template &lt;class Mutex&gt;<br>    void swap(unique_lock&lt;Mutex&gt;&amp; x, unique_lock&lt;Mutex&gt;&amp; y)<ins> noexcept</ins>;<br>...<br>}<br></pre>
<h2>30.4.1.2.1 Class mutex [thread.mutex.class]</h2>
Before p. 1
<pre>namespace std {<br>  class mutex {<br>  public:<br>    constexpr mutex()<ins> noexcept</ins>;<br>    ~mutex();<br><br>    mutex(const mutex&amp;) = delete;<br>    mutex&amp; operator=(const mutex&amp;) = delete;<br><br>    void lock();<br>    bool try_lock()<del> noexcept</del>;<br>    void unlock()<del> noexcept</del>;<br><br>    typedef implementation-defined native_handle_type; // See 30.2.3<br>    native_handle_type native_handle(); // See 30.2.3<br>  };<br>}<br></pre>
<h2>30.4.1.2.2 Class recursive_mutex [thread.mutex.recursive]</h2>
Before p.1
<pre>namespace std {<br>  class recursive_mutex {<br>  public:<br>    recursive_mutex();<br>    ~recursive_mutex();<br><br>    recursive_mutex(const recursive_mutex&amp;) = delete;<br>    recursive_mutex&amp; operator=(const recursive_mutex&amp;) = delete;<br><br>    void lock();<br>    bool try_lock() noexcept;<br>    void unlock()<del> noexcept</del>;<br><br>    typedef implementation-defined native_handle_type; // See 30.2.3<br>    native_handle_type native_handle(); // See 30.2.3<br>  };<br>}<br></pre>
<h2>30.4.1.3.1 Class timed_mutex [thread.timedmutex.class]</h2>
Before p. 1
<pre>namespace std {<br>  class timed_mutex {<br>  public:<br>    timed_mutex();<br>    ~timed_mutex();<br><br>    timed_mutex(const timed_mutex&amp;) = delete;<br>    timed_mutex&amp; operator=(const timed_mutex&amp;) = delete;<br><br>    void lock();<br>    bool try_lock();<br>    template &lt;class Rep, class Period&gt;<br>      bool try_lock_for(const chrono::duration&lt;Rep, Period&gt;&amp; rel_time)<del> noexcept</del>;<br>    template &lt;class Clock, class Duration&gt;<br>      bool try_lock_until(const chrono::time_point&lt;Clock, Duration&gt;&amp; abs_time)<del> noexcept</del>;<br>    void unlock();<br><br>    typedef implementation-defined native_handle_type; // See 30.2.3<br>    native_handle_type native_handle(); // See 30.2.3<br>  };<br>}<br></pre>
<h2>30.4.1.3.2 Class recursive_timed_mutex [thread.timedmutex.recursive]</h2>
Before p. 1
<pre>namespace std {<br>  class recursive_timed_mutex {<br>  public:<br>    recursive_timed_mutex();<br>    ~recursive_timed_mutex();<br><br>    recursive_timed_mutex(const recursive_timed_mutex&amp;) = delete;<br>    recursive_timed_mutex&amp; operator=(const recursive_timed_mutex&amp;) = delete;<br><br>    void lock();<br>    bool try_lock()<ins> noexcept</ins>;<br>    template &lt;class Rep, class Period&gt;<br>      bool try_lock_for(const chrono::duration&lt;Rep, Period&gt;&amp; rel_time)<del> noexcept</del>;<br>    template &lt;class Clock, class Duration&gt;<br>      bool try_lock_until(const chrono::time_point&lt;Clock, Duration&gt;&amp; abs_time)<del> noexcept</del>;<br>    void unlock();<br><br>    typedef implementation-defined native_handle_type; // See 30.2.3<br>    native_handle_type native_handle(); // See 30.2.3<br>  };<br>}<br></pre>
<h2>30.4.2.1 Class template lock_guard [thread.lock.guard]</h2>
Before p. 1
<pre>namespace std {<br>  template &lt;class Mutex&gt;<br>  class lock_guard {<br>  public:<br>...<br>    lock_guard(mutex_type&amp; m, adopt_lock_t)<del> noexcept</del>;<br>...<br>  };<br>}<br></pre>
After p. 5
<pre>lock_guard(mutex_type&amp; m, adopt_lock_t)<del> noexcept</del>;<br>  Requires: The calling thread owns the mutex m.<br>  Postcondition: &amp;pm == &amp;m<br>  <ins>Throws: Nothing.</ins><span
 style="color: rgb(51, 204, 0); text-decoration: underline;"></span><br></pre>
<h2>30.4.2.2 Class template unique_lock [thread.lock.unique]</h2>
Before p. 1
<pre>namespace std {<br>  template &lt;class Mutex&gt;<br>  class unique_lock {<br>  public:<br>...<br>    // 30.4.2.2.1, construct/copy/destroy:<br>    unique_lock() noexcept;<br>    explicit unique_lock(mutex_type&amp; m);<br>    unique_lock(mutex_type&amp; m, defer_lock_t) noexcept;<br>    unique_lock(mutex_type&amp; m, try_to_lock_t)<del> noexcept</del>;<br>    unique_lock(mutex_type&amp; m, adopt_lock_t)<del> noexcept</del>;<br>    template &lt;class Clock, class Duration&gt;<br>      unique_lock(mutex_type&amp; m, const chrono::time_point&lt;Clock, Duration&gt;&amp; abs_time)<del> noexcept</del>;<br>    template &lt;class Rep, class Period&gt;<br>      unique_lock(mutex_type&amp; m, const chrono::duration&lt;Rep, Period&gt;&amp; rel_time)<del> noexcept</del>;<br>    ~unique_lock();<br>...<br>  };<br>}<br></pre>
<h2>30.4.2.2.1 unique_lock constructors, destructor, and assignment
[thread.lock.unique.cons]</h2>
After p. 7
<pre>unique_lock(mutex_type&amp; m, try_to_lock_t)<del> noexcept</del>;<br><br>After p. 10<br></pre>
<pre>unique_lock(mutex_type&amp; m, adopt_lock_t)<del> noexcept</del>;<br>  Requires: The calling thread own the mutex.<br>  Effects: Constructs an object of type unique_lock.<br>  Postconditions: pm<br>  <ins>Throws: Nothing.</ins><ins></ins><br></pre>
After p. 13
<pre>template &lt;class Clock, class Duration&gt;<br>  unique_lock(mutex_type&amp; m, const chrono::time_point&lt;Clock, Duration&gt;&amp; abs_time)<del> noexcept</del>;<br></pre>
After p. 16
<pre>template &lt;class Rep, class Period&gt;<br>unique_lock(mutex_type&amp; m, const chrono::duration&lt;Rep, Period&gt;&amp; rel_time)<del> noexcept</del>;<br></pre>
<h2>30.6.1 Overview [futures.overview]</h2>
After p. 1
<pre>namespace std {<br>...<br>  template &lt;class R&gt;<br>    void swap(promise&lt;R&gt;&amp; x, promise&lt;R&gt;&amp; y)<ins> noexcept</ins>;<br>...<br>  template &lt;class R&gt;<br>    void swap(packaged_task&lt;R(ArgTypes...)<ins>&gt;</ins>&amp;, packaged_task&lt;R(ArgTypes...)&gt;&amp;)<ins> noexcept</ins>;<br>...<br>}<br></pre>
<h2>30.6.2 Error handling</h2>
Before p.1
<pre>const error_category&amp; future_category()<ins> noexcept</ins>;</pre>
After p. 2
<pre>error_code make_error_code(future_errc e)<ins> noexcept</ins>;</pre>
After p. 3
<pre>error_condition make_error_condition(future_errc e)<ins> noexcept</ins>;</pre>
<h2>30.6.5 Class template promise [futures.promise]</h2>
After p. 27
<pre>template &lt;class R&gt;<br>  void swap(promise&lt;R&gt;&amp; x, promise&lt;R&gt;&amp; y)<ins> noexcept</ins>;<br></pre>
<h2>30.6.6 Class template future [futures.unique_future]</h2>
After p. 3
<pre>namespace std {<br>  template &lt;class R&gt;<br>  class future {<br>  public:<br>    future()<ins> noexcept</ins>;<br>    future(future &amp;&amp;)<ins> noexcept</ins>;<br>    future(const future&amp; rhs) = delete;<br>    ~future();<br>    future&amp; operator=(const future&amp; rhs) = delete;<br>    future&amp; operator=(future&amp;&amp;) noexcept;<br>    shared_future<r> share() &amp;&amp;;<br><br>    // retrieving the value<br>    see below get();<br><br>    // functions to check state<br>    bool valid() const<ins> noexcept</ins>;<br><br>    void wait() const;<br>    ...<br>  };<br>}<br></r></pre>
After p. 4
<pre>future()<ins> noexcept</ins>;<br></pre>
After p. 9
<pre>future&amp; operator=(future&amp;&amp; rhs)<ins> noexcept</ins>;<br></pre>
After p. 17
<pre>bool valid() const<ins> noexcept</ins>;<br></pre>
<h2>30.6.7 Class template shared_future [futures.shared_future]</h2>
After p. 3
<pre>namespace std {<br>  template &lt;class R&gt;<br>  class shared_future {<br>  public:<br>    shared_future() noexcept;<br>    shared_future(const shared_future&amp; rhs);<br>    shared_future(future&lt;R&gt;&amp;&amp;) noexcept;<br>    shared_future(shared_future&amp;&amp; rhs) noexcept;<br>    ~shared_future();<br>    shared_future&amp; operator=(const shared_future&amp; rhs);<br>    shared_future&amp; operator=(shared_future&amp;&amp; rhs)<ins> noexcept</ins>;<br><br>    // retrieving the value<br>    see below get() const;<br><br>    // functions to check state<br>    bool valid() const<ins> noexcept</ins>;<br><br>    void wait() const;<br>    ...<br>  };<br>}<br></pre>
After p. 11
<pre>shared_future&amp; operator=(shared_future&amp;&amp; rhs)<ins> noexcept</ins>;<br></pre>
After p. 20
<pre>bool valid() const<ins> noexcept</ins>;<br></pre>
<h2>30.6.9 Class template packaged_task [futures.task]</h2>
After p.2
<pre>namespace std {<br>  template&lt;class R, class... ArgTypes&gt;<br>  class packaged_task&lt;R(ArgTypes...)&gt; {<br>  public:<br>...<br>    // move support<br>    packaged_task(packaged_task&amp;&amp; other) noexcept;<br>    packaged_task&amp; operator=(packaged_task&amp;&amp; other)<ins> noexcept</ins>;<br>    void swap(packaged_task&amp; other) noexcept;<br>...<br>  };<br>}<br></pre>
After p. 6
<pre>packaged_task&amp; operator=(packaged_task&amp;&amp; other)<ins> noexcept</ins>;<br></pre>
</body>
</html>
