Идея проста: позволить двойную проверку(double check).
| RetroEvent.h |
| #pragma once
#include <Windows.h>
#include <intrin.h>
class RetroEvent
{
public:
RetroEvent();
~RetroEvent();
__int64 RequestWait();
DWORD PerformWait(__int64 index, DWORD timeout);
void Set();
private:
__int64 m_setIndex, m_waitIndex, m_waitingCount;
HANDLE m_eventHandle;
};
|
| |
| RetroEvent.cpp |
| #include "stdafx.h"
#include "RetroEvent.h"
RetroEvent::RetroEvent()
{
m_eventHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
m_setIndex = 0;
m_waitIndex = 0;
m_waitingCount = 0;
}
RetroEvent::~RetroEvent()
{
CloseHandle(m_eventHandle);
}
__int64 RetroEvent::RequestWait()
{
return ::InterlockedIncrement64(&m_waitIndex);
}
DWORD RetroEvent::PerformWait(__int64 index, DWORD timeout)
{
DWORD begin = GetTickCount();
DWORD res = STATUS_WAIT_0;
while (true)
{
::InterlockedIncrement64(&m_waitingCount);
if (::InterlockedCompareExchange64(&m_setIndex, 0, 0) > index)
{
::InterlockedDecrement64(&m_waitingCount);
break;
}
DWORD now = GetTickCount();
if ((now - begin) > timeout)
{
::InterlockedDecrement64(&m_waitingCount);
SetLastError(WAIT_TIMEOUT);
res = WAIT_TIMEOUT;
break;
}
DWORD toWait = timeout - (now - begin);
res = WaitForSingleObject(m_eventHandle, toWait);
if (res != STATUS_WAIT_0)
{
::InterlockedDecrement64(&m_waitingCount);
break;
}
if(::InterlockedDecrement64(&m_waitingCount) == 0)
continue;
while (::InterlockedCompareExchange64(&m_waitingCount, 0, 0)) SwitchToThread();
}
return res;
}
void RetroEvent::Set()
{
__int64 setIndex = RequestWait();
__int64 prevIndex = m_setIndex;
if (prevIndex > setIndex)
return;
if (::InterlockedCompareExchange64(&m_setIndex, setIndex, prevIndex) != prevIndex)
return;
::InterlockedIncrement64(&m_waitingCount);
SetEvent(m_eventHandle);
while (::InterlockedCompareExchange64(&m_waitingCount, 0, 0) > 1)
{
if (::InterlockedCompareExchange64(&m_setIndex, 0, 0) != setIndex)
{
::InterlockedDecrement64(&m_waitingCount);
return;
}
SwitchToThread();
}
ResetEvent(m_eventHandle);
::InterlockedDecrement64(&m_waitingCount);
}
|
| |
Буду рад как критике, так и ссылкам на другие готовые реализации.