gpt4 book ai didi

c++ - 使用 native Windows API 的 win32 线程安全队列实现

转载 作者:可可西里 更新时间:2023-11-01 10:38:34 24 4
gpt4 key购买 nike

由于windows缺少条件变量(虽然从vis​​ta开始引入,但windows XP和2003不支持),用c++实现线程安全的队列不是很容易。 Strategies for Implementing POSIX Condition Variables on Win32 .我需要的是只使用 CriticalSection 或 Mutex 和 Event,而不使用信号量和条件变量。

我也试图找到一个只使用 win32 native API 的确切实现,但没有成功。所以我自己完成了一个。问题是我不是 100% 确定代码是线程安全的。谁能告诉我好不好?

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;
}

最佳答案

在 Windows 中实现线程安全队列很简单。我已经在 Delphi、C++、BCB 等中完成了。

为什么您认为需要条件变量?您认为 Windows 消息队列如何工作?

事件是用于 P-C 队列的错误原语。最简单/最清晰的方法是使用信号量。

简单的无界生产者-消费者队列。

template <typename T> class PCSqueue{
CRITICAL_SECTION access;
deque<T> *objectQueue;
HANDLE queueSema;
public:
PCSqueue(){
objectQueue=new deque<T>;
InitializeCriticalSection(&access);
queueSema=CreateSemaphore(NULL,0,MAXINT,NULL);
};
void push(T ref){
EnterCriticalSection(&access);
objectQueue->push_front(ref);
LeaveCriticalSection(&access);
ReleaseSemaphore(queueSema,1,NULL);
};
bool pop(T *ref,DWORD timeout){
if (WAIT_OBJECT_0==WaitForSingleObject(queueSema,timeout)) {
EnterCriticalSection(&access);
*ref=objectQueue->back();
objectQueue->pop_back();
LeaveCriticalSection(&access);
return(true);
}
else
return(false);
};
};

编辑——有界队列不会更难——你需要另一个信号量来计算空位。我不使用有界队列,但我确信它没问题 - 具有 2 个信号量和一个互斥锁/CS 的有界队列是标准模式。

编辑:使用 PostMessage() 或 PostThreadMessage() API 调用 - 它们明确声明不受“waveOutProc”回调的影响。 MSDN 说调用“其他波函数”会导致死锁——信号量调用不在那个集合中,如果允许 SetEvent() 但不允许 ReleaseSemaphore() ,我确实会感到非常惊讶。事实上,如果允许 SetEvent() 而 ReleaseSemaphore() 在 Windows 中不是任何地方,我会感到惊讶。

关于c++ - 使用 native Windows API 的 win32 线程安全队列实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11706985/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com