<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html><head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">

    <title>P0290R3: apply() for synchronized_value&lt;T&gt;</title>
    <style type="text/css">
      p {text-align:justify}
      li {text-align:justify}
      blockquote.note
      {
      background-color:#E0E0E0;
      padding-left: 15px;
      padding-right: 15px;
      padding-top: 1px;
      padding-bottom: 1px;
      }
      ins, .inserted
      {
      color: black;
      background: #a0ffa0;
      text-decoration: underline;
      }
      del
      {
      color: black;
      background: #ffa0a0;
      text-decoration: line-through;
      }
    </style>
  </head><body>
    <table>
      <tr><td>Document Number:</td><td>P0290R3</td></tr>
      <tr><td>Date:</td><td>2023-01-06</td></tr>
      <tr><td>Author:</td><td><a href="mailto:anthony@justsoftwaresolutions.co.uk">Anthony
            Williams</a></td></tr>
      <tr><td>Audience:</td><td>SG1</td></tr>
    </table>
    <h1>P0290R3: <code>apply()</code> for <code>synchronized_value&lt;T&gt;</code></h1>

    <h2>Introduction</h2>

    <p>This paper is a followup to <a href="http://wg21.link/p0290r2">P0290R2</a>, based on feedback
      from the Kona 2022 meeting.</p>
    
    <p>The basic idea is that <code>synchronized_value&lt;T&gt;</code> stores a value of
      type<code>T</code> and a mutex.The <code>apply()</code> function then provides a means of
      accessing the stored value with the mutex locked, automatically unlocking the mutex
      afterwards.</p>

    <p>The <code>apply()</code> function is variadic, so you can operate on a set
      of <code>synchronized_value&lt;T&gt;</code> objects. All the mutexes are locked prior to
      invoking the supplied callable object, and then they are all released
      afterwards.</p>

    <p>The name is chosen to fit in with <code>std::apply</code> for tuples,
      since the operation is conceptually similar.  Rather than expanding
      a <code>std::tuple</code> to supply the arguments to the function, the
      values wrapped by the <code>synchronized_value</code>s are extracted to
      supply the arguments to the function.</p>

    <p>This provides an easy way for developers to ensure that all accesses to a given object are
      done with the relevant mutex locked, whilst also allowing for operations that require locks on
      multiple objects.</p>

    <p>In order to avoid simple mistakes when using the <code>synchronized_value&lt;T&gt;</code>
      objects, there are no public member functions or operations other than construction.</p>

    <p>The actual implementation may use an alternative synchronization mechanism instead of a
    mutex, provided that the synchronization requirements are met.</p>

    <h2>Examples</h2>

    <h3>1: Simple accesses</h3>
    <p>Simple accesses can be done with simple lambdas:</p>

    <pre>
synchronized_value&lt;std::string&gt; s;

std::string read_value(){
    return apply([](auto&amp; x){return x;},s);
}

void set_value(std::string const& new_val){
    apply([&amp;](auto&amp; x){x=new_val;},s);
}
    </pre>

    <h3>2: More complex processing</h3>
    
    <p>More complex processing can be done with a more complex lambda, or a separate function or
      callable object:</p>

    <pre>
synchronized_value&lt;std::queue&lt;message_type&gt;&gt; queue;
      
void process_message(){
    std::optional&lt;message_type&gt; local_message;
    apply([&amp;](std::queue&lt;message_type&gt;&amp; q){
        if(!q.empty()){
            local_message.emplace(std::move(q.front()));
            q.pop_front();
        }
    },queue);
    if(local_message)
        do_processing(local_message.value());
}
    </pre>

    <h3>3: Multi-value processing</h3>

    <p>The variadic nature of <code>apply()</code> means that writing code that accesses
      multiple <code>synchronized_value&lt;T&gt;</code> objects is straightforward. It uses the same
      mechanism as <code>std::lock()</code> to ensure that the requisite mutexes are locked without
      deadlock.</p>

    <p>The ubiquitous example of transferring money between accounts can then be simply written as a
      follows:</p>

    <pre>
void transfer_money(
    synchronized_value&lt;account&gt;&amp; from_,
    synchronized_value&lt;account&gt;&amp; to_,
    money_value amount){
    apply([=](auto&amp; from,auto&amp; to){
        from.withdraw(amount);
        to.deposit(amount);
    },from_,to_);
}
    </pre>

    <h2>Proposed wording</h2>

<p>Add a new section to chapter 30 as follows.</p>

<blockquote class="inserted">
  <h3>30.x Synchronized Values</h3>
  <p>This section describes a class template to provide locked access to a value in order to
    facilitate the construction of race-free programs.</p>

  <h4>Header &lt;synchronized_value&gt; synopsis</h4>

<pre>
namespace std {
    template&lt;class T&gt;
    class synchronized_value;

    template&lt;class F,class FirstValue,class ... OtherValues&gt;
    decltype(auto) apply(
        F&amp;&amp; f,synchronized_value&lt;FirstValue&gt;&amp; first_value,synchronized_value&lt;ValueTypes&gt;&amp;... other_values);
}
</pre>

<h4>30.x.1 Class template <code>synchronized_value</code></h4>

<pre>
namespace std
{
    template&lt;class T&gt;
    class synchronized_value
    {
    public:
        synchronized_value(synchronized_value const&amp;) = delete;
        synchronized_value&amp; operator=(synchronized_value const&amp;) = delete;

        template&lt;class ... Args&gt;
        synchronized_value(Args&amp;&amp; ... args);
        ~synchronized_value();

    private:
        T __value; // exposition only
        std::mutex __mut; // exposition only
    };
}
</pre>

  <p>An object of type <code>synchronized_value&lt;T&gt;</code> wraps an object of
    type <code>T</code>. The wrapped object can be accessed by passing a callable object or function
    to <code>apply</code>. All such accesses are done with a lock held to ensure that only one
    thread may be accessing the wrapped object for a given <code>synchronized_value</code> at a
    time.</p>

<h5><pre>
template&lt;class ... Args&gt;
synchronized_value(Args&amp;&amp; ... args);
</pre></h5>

<dl>
  <dt>Constraints:</dt>
  <dd><code>is_constructible_v&lt;T,Args...&gt;</code> is <code>true</code></dd>
  <dt>Effects:</dt>
  <dd>Direct-non-list-initializes the contained value with <code>std::forward&lt;Args&gt;(args)...</code>.</dd>

  <dt>Throws:</dt>
  <dd>Any exceptions thrown by the selected constructor of <code>T</code>.<br>
    <code>std::system_error</code> if any necessary resources cannot be acquired.
  </dd>
</dl>

<h5><pre>
~synchronized_value();
</pre></h5>

<dl>
  <dt>Effects:</dt>
  <dd>Destroys the contained object of type <code>T</code> and <code>*this</code>.</dd>
</dl>

<h4>30.x.2 <code>apply</code> function</h4>
<h5><pre>
template&lt;class F,class FirstValue,class ... OtherValues&gt;
decltype(auto) apply(
F&amp;&amp; f,synchronized_value&lt;FirstValue&gt;&amp; first_value,synchronized_value&lt;ValueTypes&gt;&amp;... other_values);
</pre></h5>

<dl>
  <dt>Effects:</dt>
  <dd>Equivalent to:
<pre>
    scoped_lock lock(first_value.__mut,other_values.__mut...);
    return <i>INVOKE</i>(std::forward&lt;F&gt;(f),first_value.__value,other_values.__value...);
</pre>
  </dd>

  <dt>Returns:</dt>
  <dd>The return value of the invocation of <code>f</code>.</dd>

  <dt>Throws:</dt>
  <dd><code>std::system_error</code> if there was an error acquiring any of the locks. Any exceptions
    thrown by the invocation of <code>f</code>.</dd>

  <dt>Synchronization:</dt>
  <dd>Multiple threads may call <code>apply()</code> concurrently
    without external synchronization. If multiple threads
    call <code>apply()</code> concurrently passing the same
    instance(s) of <code>synchronized_value</code> then the behaviour
    is as-if they each made their call in some unspecified order. The
    completion of the full expression associated with one invocation
    of <code>apply</code> synchronizes-with a subsequent invocation
    of <code>apply</code> where the same instance
    of <code>synchronized_value</code> is passed to both invocations
    of <code>apply</code>.
    <dt>Requires:</dt>
    <dd>
    A single instance of <code>synchronized_value</code> shall not be passed more than once to the
    same invocation of <code>apply</code>. [Example:
    <pre>
      synchronized_value&lt;int&gt; sv;
      void f(int,int);
      apply(f,sv,sv); // undefined behaviour, sv passed more than once to same call
</pre>
    &mdash;End Example]<br>
    The invocation of <code>f</code> shall not call <code>apply</code> directly or
    indirectly passing any of <code>first_value, other_values...</code>.
    
  </dd>
</dl>
</blockquote>

<h2>Changes since P0290R2</h2>

  <p>Following discussion in LWG in Kona, the following changes have been made:</p>

  <ol>
    <li>Updated wording to match C++23 draft</li>
  </ol>

<h2>Changes since P0290R1</h2>

  <p>Following discussion in LEWG in Kona, the following changes have been made:</p>

  <ol>
    <li>Fixed HTML typos;</li>
    <li>Changed signature of apply so it overloads <code>std::apply</code> for
      tuples, and is a better match when a <code>synchronized_value</code> is supplied.</li>
  </ol>

<h2>Changes since P0290R0</h2>

  <p>Following discussion in SG1 in Oulu, the following changes have been made:</p>

  <ol>
    <li>The wording has been changed to allow alternative synchronization mechanisms instead of
      mutexes;</li>
    <li>Calling <code>apply</code> with the same <code>synchronized_value</code> more than once in
      the same argument list is explicitly disallowed;</li>
    <li>Recursively calling <code>apply</code> with an overlapping set
      of <code>synchronized_value</code> objects is explicitly disallowed; and</li>
    <li>Constructing a <code>synchronized_value</code> may throw <code>std::system_error</code>.</li>
  </ol>
  
    </body></html>
    
    
