由于Windows中缺少条件变量(尽管自Vista以来引入,但不支持Windows XP和2003),因此在C++中实现线程安全队列并不是很容易。可以参考在Win32上实现POSIX条件变量的策略。我所需要的仅是使用CriticalSection或Mutex和Event而不是semaphore和条件变量。
我也试图找到一个只使用Win32本地API的确切实现,但没有成功。因此,我自己完成了一个。问题是,我不能确定这段代码是否是线程安全的。谁能告诉我它是否可行?
我也试图找到一个只使用Win32本地API的确切实现,但没有成功。因此,我自己完成了一个。问题是,我不能确定这段代码是否是线程安全的。谁能告诉我它是否可行?
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(&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(&m_lock);
}
void CEventSyncQueue::Put(void* ptr)
{
::EnterCriticalSection(&m_lock);
while(m_nCapacity > 0 && m_list.GetCount() >= m_nCapacity)
{
::LeaveCriticalSection(&m_lock);
//wait
if(::WaitForSingleObject(m_hPutEvent, INFINITE) != WAIT_OBJECT_0)
{
ASSERT(FALSE);
}
::EnterCriticalSection(&m_lock);
}
if(m_nCapacity > 0)
{
ASSERT(m_list.GetCount() < m_nCapacity);
}
m_list.AddTail(ptr);
::SetEvent(m_hGetEvent); //notifyAll
::LeaveCriticalSection(&m_lock);
}
void* CEventSyncQueue::Get()
{
::EnterCriticalSection(&m_lock);
while(m_list.IsEmpty())
{
::LeaveCriticalSection(&m_lock);
//wait
if(::WaitForSingleObject(m_hGetEvent, INFINITE) != WAIT_OBJECT_0)
{
ASSERT(FALSE);
}
::EnterCriticalSection(&m_lock);
}
ASSERT(!m_list.IsEmpty());
void* ptr = m_list.RemoveHead();
::SetEvent(m_hPutEvent); //notifyAll
::LeaveCriticalSection(&m_lock);
return ptr;
}