title: Notifying a consumer thread before or after releasing the lock on the mutex?
body: <p>Below is listing 4.5 from the book <em>C++ concurrency in action</em> that defines a thread-safe queue using condition variables.</p>
  
  <pre><code>#include &lt;mutex&gt;
  #include &lt;condition_variable&gt;
  #include &lt;queue&gt;
  #include &lt;memory&gt;
  
  template&lt;typename T&gt;
  class threadsafe_queue
  {
  private:
      mutable std::mutex mut;
      std::queue&lt;T&gt; data_queue;
      std::condition_variable data_cond;
  public:
      threadsafe_queue()
      {}
      threadsafe_queue(threadsafe_queue const&amp; other)
      {
          std::lock_guard&lt;std::mutex&gt; lk(other.mut);
          data_queue=other.data_queue;
      }
  
      void push(T new_value)
      {
          std::lock_guard&lt;std::mutex&gt; lk(mut);
          data_queue.push(new_value);
          data_cond.notify_one();
      }
  
      void wait_and_pop(T&amp; value)
      {
          std::unique_lock&lt;std::mutex&gt; lk(mut);
          data_cond.wait(lk,[this]{return !data_queue.empty();});
          value=data_queue.front();
          data_queue.pop();
      }
  
  std::shared_ptr&lt;T&gt; wait_and_pop()
  {
      std::unique_lock&lt;std::mutex&gt; lk(mut);
      data_cond.wait(lk,[this]{return !data_queue.empty();});
      std::shared_ptr&lt;T&gt; res(std::make_shared&lt;T&gt;(data_queue.front()));
      data_queue.pop();
      return res;
  }
  
  bool try_pop(T&amp; value)
  {
      std::lock_guard&lt;std::mutex&gt; lk(mut);
      if(data_queue.empty)
          return false;
      value=data_queue.front();
      data_queue.pop();
  }
  
  std::shared_ptr&lt;T&gt; try_pop()
  {
      std::lock_guard&lt;std::mutex&gt; lk(mut);
      if(data_queue.empty())
          return std::shared_ptr&lt;T&gt;();
      std::shared_ptr&lt;T&gt; res(std::make_shared&lt;T&gt;(data_queue.front()));
      data_queue.pop();
      return res;
  }
  
  bool empty() const
  {
      std::lock_guard&lt;std::mutex&gt; lk(mut);
      return data_queue.empty();
  }
  };
  
  int main()
  {}
  </code></pre>
  
  <p>In the push function, another thread is being notified while the mutex is still locked. Isn't it better to notify popper threads right after the mutex is released. For example, like this:</p>
  
  <pre><code>void push(T new_value)
  {
      {
          std::lock_guard&lt;std::mutex&gt; lk(mut)
          data_queue.push(new_value);
      }
      data_cond.notify_one();
  }
  </code></pre>
  
  <p>I am aware that they are functionally do the same thing. I'm thinking in the original case, the consumer thread will receive a false notification that eventually makes it to try locking the mutex more than once. However, in the second case, we avoid waking up the consumer thread early, and therefore, tries to lock the mutex can be successful in the very first time.</p>