title: win32 thread-safe queue implementation using native windows API
body: <p>Because the lack of condition variable in windows(though it is introduced since vista, it's not supported in windows XP and 2003), it is not very easy to implement a thread-safe queue in c++. <a href="http://www.cs.wustl.edu/~schmidt/win32-cv-1.html" rel="nofollow">Strategies for Implementing POSIX Condition Variables on Win32</a>. What I required is to just use CriticalSection or Mutex and Event without using semaphore and condition variable.</p>
  
  <p>I also tried to find an exact implementation that just using win32 native API, but no luck. So I finished one by myself. The problem is I am not 100% sure the code is thread-safe. Who can tell me it is OK or not?</p>
  
  <pre><code>class CEventSyncQueue
  {
  public:
      CEventSyncQueue(int nCapacity = -1);
      virtual ~CEventSyncQueue();
      virtual void Put(void* ptr);
      virtual void* Get();
  protected:
      int m_nCapacity;
      CPtrList m_list;
  
      CRITICAL_SECTION m_lock;    
      HANDLE m_hGetEvent;
      HANDLE m_hPutEvent;
  };
  
  CEventSyncQueue::CEventSyncQueue(int nCapacity)
  {
      m_nCapacity = nCapacity;
  
      ::InitializeCriticalSection(&amp;m_lock);
      m_hPutEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
      m_hGetEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
  }
  
  CEventSyncQueue::~CEventSyncQueue()
  {
      m_list.RemoveAll();
  
      ::CloseHandle(m_hGetEvent);
      ::CloseHandle(m_hPutEvent);
  
      ::DeleteCriticalSection(&amp;m_lock);
  }
  
  void CEventSyncQueue::Put(void* ptr)
  {
      ::EnterCriticalSection(&amp;m_lock);
  
      while(m_nCapacity &gt; 0 &amp;&amp; m_list.GetCount() &gt;= m_nCapacity)
      {
          ::LeaveCriticalSection(&amp;m_lock);
  
          //wait
          if(::WaitForSingleObject(m_hPutEvent, INFINITE) != WAIT_OBJECT_0)
          {
              ASSERT(FALSE);
          }
  
          ::EnterCriticalSection(&amp;m_lock);
      }
      if(m_nCapacity &gt; 0)
      {
          ASSERT(m_list.GetCount() &lt; m_nCapacity);
      }
      m_list.AddTail(ptr);
  
      ::SetEvent(m_hGetEvent);    //notifyAll
      ::LeaveCriticalSection(&amp;m_lock);
  }
  void* CEventSyncQueue::Get()
  {
      ::EnterCriticalSection(&amp;m_lock);
  
      while(m_list.IsEmpty())
      {
          ::LeaveCriticalSection(&amp;m_lock);
  
          //wait
          if(::WaitForSingleObject(m_hGetEvent, INFINITE) != WAIT_OBJECT_0)
          {
              ASSERT(FALSE);
          }
  
          ::EnterCriticalSection(&amp;m_lock);
      }
      ASSERT(!m_list.IsEmpty());
      void* ptr = m_list.RemoveHead();
  
      ::SetEvent(m_hPutEvent);    //notifyAll
      ::LeaveCriticalSection(&amp;m_lock);
  
      return ptr;
  }
  </code></pre>