title: Ensuring that only one instance of a function is running?
body: <p>I'm just getting into concurrent programming. Most probably my issue is very common, but since I can't find a good name for it, I can't google it.</p>
  
  <p>I have a C++ UWP application where I try to apply MVVM pattern, but I guess that the pattern or even being UWP is not relevant.</p>
  
  <p>First, I have a service interface that exposes an operation:</p>
  
  <pre><code>struct IService
  {
      virtual task&lt;int&gt; Operation() = 0;
  };
  </code></pre>
  
  <p>Of course, I provide a concrete implementation, but it is not relevant for this discussion. The operation is potentially long-running: it makes an HTTP request.</p>
  
  <p>Then I have a class that uses the service (again, irrelevant details omitted):</p>
  
  <pre><code>class ViewModel
  {
      unique_ptr&lt;IService&gt; service;
  public:
      task&lt;void&gt; Refresh();
  };
  </code></pre>
  
  <p>I use coroutines:</p>
  
  <pre><code>task&lt;void&gt; ViewModel::Refresh()
  {
      auto result = co_await service-&gt;Operation();
      // use result to update UI
  }
  </code></pre>
  
  <p>The Refresh function is invoked on timer every minute, or in response to a user request. What I want is: if a Refresh operation is already in progress when a new one is started or requested, then abandon the second one and just wait for the first one to finish (or time out). In other words, I don't want to queue all the calls to Refresh - if a call is already in progress, I prefer to skip a call until the next timer tick.</p>
  
  <p>My attempt (probably very naive) was:</p>
  
  <pre><code>mutex refresh;
  task&lt;void&gt; ViewModel::Refresh()
  {
      unique_lock&lt;mutex&gt; lock(refresh, try_to_lock);
      if (!lock)
      {
          // lock.release(); commented out as harmless but useless =&gt; irrelevant
          co_return;
      }
      auto result = co_await service-&gt;Operation();
      // use result to update UI
  }
  </code></pre>
  
  <p><strong>Edit after the original post: I commented out the line in the code snippet above, as it makes no difference. The issue is still the same.</strong></p>
  
  <p>But of course an assertion fails: <code>unlock of unowned mutex</code>. I guess that the problem is the <code>unlock</code> of <code>mutex</code> by <code>unique_lock</code> destructor, which happens in the continuation of the coroutine and on a different thread (other than the one it was originally locked on).</p>
  
  <p>Using Visual C++ 2017.</p>