我有一个自动重置事件对象,如下所示:
handle = CreateEvent(NULL, true, false, NULL);
...和(对于某些单元测试目的)我想检查它是否在某一点发出信号。我知道使用事件的“正确”方式 - 这纯粹是为了诊断工具。
对于手动重置事件,我可以使用......
bool signalled = WaitForSingleObjectEx(handle, 0, true) != WAIT_TIMEOUT;
...但是对于具有重置它们的副作用的自动重置事件。我想我可以试试这个,但我觉得应该有一个不那么危险的方式......?
bool isSignalled(HANDLE handle)
{
bool signalled = WaitForSingleObjectEx(handle, 0, true) != WAIT_TIMEOUT;
// warning - event is now reset. Maybe need to wrap this in a critical section or similar?
if (signalled)
SetEvent(handle);
return signalled;
}
答案 0 :(得分:3)
更新:
咖啡已经踢了,我错了!
使用具有超时零的WaitForSingleObject来确定是否已发出事件信号将导致信号被清除(如果事件已发出信号(及其AutoReset事件))。您可以通过简单地连续两次调用WaitForSingleObject来验证这一点。
在为AutoReset初始化的事件将重置之前,必须释放等待线程。
http://msdn.microsoft.com/en-us/library/ms682396(VS.85).aspx
当你以超时零调用WaitForSingleObjectEx时,你的线程不会成为服务员。
http://msdn.microsoft.com/en-us/library/ms687036(VS.85).aspx
如果dwMilliseconds为零,则为 功能不进入等待状态 如果不符合标准;它永远 马上回来。
答案 1 :(得分:3)
我没有看到一种简单的方法。您可以“模拟”该事件以进行测试。
将事件包装在C ++对象中,并更改所有代码以使用其方法。
class MockEvent {
public:
MockEvent () : m_handle(::CreateEvent(NULL, TRUE, FALSE, NULL) {}
~MockEvent () { ::CloseHandle(m_handle); }
BOOL Set() { return ::SetEvent(m_handle); }
DWORD Wait(DWORD timeout = INFINITE) {
return ::WaitForSingleObject(m_handle, timeout);
}
private:
HANDLE m_handle;
// Do not implement copy or assignment:
MockEvent(const MockEvent &);
MockEvent &operator=(const MockEvent &);
};
然后你会想要使用某种引用计数指针,它可以传递并复制原始HANDLE的方式:
typedef std::tr1::shared_ptr<MockEvent> MockEventPtr;
将使用原始HANDLE的所有代码替换为MockEventPtr。
// Original code:
HANDLE hEvent = CreateEvent(NULL, true, false, NULL);
// Becomes:
MockEventPtr pEvent(new MockEvent);
// Original code:
SetEvent(hEvent);
// Becomes:
pEvent->Set();
等等。
现在,对于诊断工具,您可以扩展MockEvent以跟踪状态并公开方法以显示当前状态。
class MockEvent {
public:
MockEvent () :
m_handle(::CreateEvent(NULL, TRUE, FALSE, NULL),
m_signaled(false) {
::InitializeCriticalSection(&m_cs);
}
~MockEvent () {
::DeleteCriticalSection(&m_cs);
::CloseHandle(m_handle);
}
BOOL Set() {
::EnterCriticalSection(&m_cs);
m_signaled = true;
BOOL result = ::SetEvent(m_handle);
::LeaveCriticalSection(&m_cs);
return result;
}
DWORD Wait(DWORD timeout = INFINITE) {
::EnterCriticalSection(&m_cs);
DWORD result = ::WaitForSingleObject(m_handle, timeout);
if (result == WAIT_OBJECT_0) {
m_signaled = false;
}
::LeaveCriticalSection(&m_cs);
return result;
}
// The result of this may be obsolete by the time you get it.
bool IsSignaled() const { return m_signaled; }
private:
HANDLE m_handle;
bool m_signaled;
CRITICAL_SECTION m_cs;
// Do not implement copy or assignment:
MockEvent(const MockEvent &);
MockEvent &operator=(const MockEvent &);
};
这是未经测试的代码。在实际代码中,我也将包装CRITICAL_SECTION。请注意,如果另一个线程更改状态,IsSignaled的结果可能在您获得它的那一刻就已过时。我假设这是用于测试代码,该代码将在状态应该是特定方式时进行检查。