title: Make scope of lock smaller in threadsafe queue
body: <p>I have a dll which has a high priority functionality that runs in a high priority thread. This dll needs to report progress. Basically a callback system is used. The issue is that the dll has no control over the amount of time the callback takes to complete. This means the high priority functionality is dependent on the implementation of the callback which is not acceptable.</p>
  
  <p>The idea is to have a class inbetween that buffers the progress notifications and calls the callback.</p>
  
  <p>I'm new to C++11 and it's threading functionality and trying to discover the possibilities. I have an implementation but I have an issue(at least one that I see now). When the thread awakens after the wait the mutex is reacquired and stays acquired until the next wait. This means the lock is acquired for as long as the lengthy operation continues. Adding progress will block here. Basically a lot of code for no gain. I thought of changing the code to this but I don't know if this is the correct implementation.</p>
  
  <pre><code>        Progress progress = queue.front();
          queue.pop();
          lock.unlock();
          // Do lengthy operation with progress
          lock.lock();
  </code></pre>
  
  <p>I think I need to wait for the condition variable, but that should not be connected to the lock. I don't see how this can be done. Pass a dummy lock and use a different lock to protect the queue? How should this problem be tackled in C++11?</p>
  
  <p>header file</p>
  
  <pre><code>#include &lt;atomic&gt;
  #include &lt;condition_variable&gt;
  #include &lt;mutex&gt;
  #include &lt;thread&gt;
  #include &lt;queue&gt;
  
  #include "Error.h"
  #include "TypeDefinitions.h"
  
  
  struct Progress
  {
      StateDescription State;
      uint8 ProgressPercentage;
  };
  
  class ProgressIsolator
  {
  public:
      ProgressIsolator();
      virtual ~ProgressIsolator();
  
      void ReportProgress(const Progress&amp; progress);
      void Finish();
  
  private:
      std::atomic&lt;bool&gt; shutdown;
      std::condition_variable itemAvailable;
      std::mutex mutex;
      std::queue&lt;Progress&gt; queue;
      std::thread worker;
  
      void Work();
  };
  </code></pre>
  
  <p>cpp file</p>
  
  <pre><code>#include "ProgressIsolator.h"
  
  ProgressIsolator::ProgressIsolator() :
      shutdown(false),
      itemAvailable(),
      worker([this]{ Work(); }),
      progressCallback(progressCallback),
      completedCallback(completedCallback)
  {
      // TODO: only continue when worker thread is ready and listening?
  }
  
  ProgressIsolator::~ProgressIsolator()
  {
      Finish();
      worker.join();
  }
  
  void ProgressIsolator::ReportProgress(const Progress&amp; progress)
  {
      std::unique_lock&lt;std::mutex&gt; lock(mutex);
      queue.push(progress);
      itemAvailable.notify_one();
  }
  
  void ProgressIsolator::Finish()
  {
      shutdown = true;
      itemAvailable.notify_one();
  }
  
  void ProgressIsolator::Work()
  {
      std::unique_lock&lt;std::mutex&gt; lock(mutex);
  
      while (!shutdown)
      {
          itemAvailable.wait(lock);
          while (!queue.empty())
          {
              Progress progress = queue.front();
              queue.pop();
              // Do lengthy operation with progress
          }
      }
  }
  </code></pre>