<!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>P0290R4: 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>P0290R4</td></tr>
      <tr><td>Date:</td><td>2023-02-10</td></tr>
      <tr><td>Author:</td><td><a href="mailto:anthony@justsoftwaresolutions.co.uk">Anthony
            Williams</a></td></tr>
      <tr><td>Audience:</td><td>LWG</td></tr>
    </table>
    <h1>P0290R4: <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/p0290r3">P0290R3</a>, based on feedback
      from LWG at the Issaquah 2023 meeting.</p>

    <p>This paper targets the Concurrency TS v2.</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>Feedback From Technical Specification</h2>

    <p>This paper is targetting the C++ Concurrency TS 2, in order to garner feedback from users and implementers. Specifically, feedback is desired for the following questions:</p>

    <ol>
      <li>Should the <code>synchronized_value</code> template be
        parameterized on the type of the <em>Lockable</em> object
        (defaulted to <code>std::mutex</code>)? This would allow use
        with third party or user-supplied mutexes, but potentially
        complicates the interface and would require a specialization
        for the default case if the implementation wanted to use
        something other than <code>std::mutex</code> for performance
        reasons.</li>
      <li>Should <code>apply</code> accept
      cv-qualified <code>synchronized_value&lt;T&gt;</code> arguments,
      as well as non-<code>const</code> arguments? This complicates
      the interface, but allows you to declare a <code>const
      synchronized_value&lt;T&gt; &amp;</code> in order to guarantee
      that you can't change the stored value through calls
      to <code>apply</code> that are given that reference.</li>
    </ol>

    <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 row to Table 1 in [general.feature.test] as follows:</p>

    <blockquote class="inserted">
      <table border=1px>
        <tr><th>Macro name</th><th>Value</th><th>Header</th></tr>
        <tr><td><code>__cpp_lib_concurrency_v2_synchronized_value</code></td><td>202302</td><td>&lt;experimental/synchronized_value&gt;</td></tr>
      </table>
    </blockquote>

<p>Add a new section as follows.</p>

<blockquote class="inserted">
  <h3>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;experimental/synchronized_value&gt; synopsis</h4>

<pre>
namespace std::experimental::inline concurrency_v2 {
    template&lt;class T&gt;
    class synchronized_value;

    template&lt;class F,class ... ValueTypes&gt;
    invoke_result_t&lt;F, ValueTypes&amp;...&gt; apply(
        F&amp;&amp; f,synchronized_value&lt;ValueTypes&gt;&amp;... values);
}
</pre>

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

<pre>
namespace std::experimental::inline concurrency_v2 {
  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);

    private:
        T <i>value</i>; // exposition only
        mutex <i>mut</i>; // exposition only
    };

template&lt;class T&gt;
synchronized_value(T)
-&gt; synchronized_value&lt;T&gt;;
}
</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><ul><li><code>(sizeof...(Args) != 1)</code> is <code>true</code> or <code>(!same_as&lt;synchronized_value,remove_cvref_t&lt;Args&gt;&gt; &amp;&amp;...)</code> is <code>true</code></li>
    <li><code>is_constructible_v&lt;T,Args...&gt;</code> is <code>true</code></li></ul>
  </dd>
  <dt>Effects:</dt>
  <dd>Direct-non-list-initializes <code><i>value</i></code> with <code>std::forward&lt;Args&gt;(args)...</code>.</dd>

  <dt>Throws:</dt>
  <dd>Any exceptions emitted by the initialization of <code><i>value</i></code>.<br>
    <code>system_error</code> if any necessary resources cannot be acquired.
  </dd>
</dl>

<h4>x.2 <code>apply</code> function</h4>
<h5><pre>
    template&lt;class F,class ... ValueTypes&gt;
    invoke_result_t&lt;F, ValueTypes&amp;...&gt; apply(
        F&amp;&amp; f,synchronized_value&lt;ValueTypes&gt;&amp;... values);
</pre></h5>

<dl>
  <dt>Constraints:</dt>
  <dd><code>sizeof...(values) != 0</code> is <code>true</code>.</dd>

  <dt>Effects:</dt>
  <dd>Equivalent to:
<pre>
    scoped_lock lock(values.<i>mut</i>...);
    return invoke(std::forward&lt;F&gt;(f),values.<i>value</i>...);
</pre>
  </dd>

    <dd>
    [Note: A single instance of <code>synchronized_value</code> can 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] &mdash;End Note]<br>
    [Note: The invocation of <code>f</code> can not call <code>apply</code> directly or
    indirectly passing any of <code>values...</code>. &mdash;End Note]
    
  </dd>
</dl>
</blockquote>

<h2>Changes since P0290R3</h2>

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

  <ol>
    <li>Updated wording to rely on effects clause rather than specify the return value, throws and synchronization properties explicitly.</li>
    <li>Added a deduction guide.</li>
    <li>Changed the template parameters to a single pack with constraints in all cases.</li>
    <li>Added a constraint to the constructor to prevent it being a move constructor or copy constructor.</li>
    <li>Corrected the header and namespace for putting in the TS rather than IS.</li>
    <li>Added a feature test macro.</li>
    <li>Added feedback questions for the TS.</li>
  </ol>
<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>
    
    
