I have an auto-reset event object created like this:
handle = CreateEvent(NULL, true, false, NULL);
...and (for some unit testing purposes) I want to check if it's signalled at a certain point. I'm aware of the 'correct' way of using events - this is purely for a diagnostic harness.
For a manual reset event I can just use...
bool signalled = WaitForSingleObjectEx(handle, 0, true) != WAIT_TIMEOUT;
...but for auto-reset events that has the side-effect of resetting them. I guess I could try this, but I have a feeling that there should be a less dangerous way...?
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;
}
The win32-event library provides an interface to Windows event objects. An event object is a synchronization object whose state can be explicitly set to a signaled state. Event objects are useful in sending a signal to a thread indicating that a particular event has occurred.
The createEvent() method creates an event object. The event must be of a legal event type, and must be initialized (dipatched) before use.
The WaitForSingleObject function returns when one of the following occurs: The specified object is in the signaled state. The time-out interval elapses.
The WaitForSingleObject function checks the current state of the specified object. If the object's state is nonsignaled, the calling thread enters the wait state until the object is signaled or the time-out interval elapses. The function modifies the state of some types of synchronization objects.
Update:
The Coffee has kicked in, and I was wrong!
Using WaitForSingleObject with a timeout of zero to determine if an event has been signaled WILL cause the signal to be cleared if the Event is signaled (and its an AutoReset event). You can verify this by simply calling WaitForSingleObject twice in a row.
A waiting thread has to be released before an Event that is intialized for AutoReset will reset.
http://msdn.microsoft.com/en-us/library/ms682396(VS.85).aspx
When you call WaitForSingleObjectEx with a timeout of zero, your thread does not become a waiter.
http://msdn.microsoft.com/en-us/library/ms687036(VS.85).aspx
If dwMilliseconds is zero, the function does not enter a wait state if the criteria is not met; it always returns immediately.
I don't see a simple way to do it. You could "mock" the event for testing purposes.
Wrap the event in an C++ object, and change all the code to use its methods.
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 &);
};
Then you'll want to use some sort of reference counted pointer that can be passed around and copied the way the original HANDLE can be:
typedef std::tr1::shared_ptr<MockEvent> MockEventPtr;
Replace all your code that uses the raw HANDLE with a MockEventPtr.
// Original code:
HANDLE hEvent = CreateEvent(NULL, true, false, NULL);
// Becomes:
MockEventPtr pEvent(new MockEvent);
// Original code:
SetEvent(hEvent);
// Becomes:
pEvent->Set();
And so on.
Now, for your diagnostic harness, you can extend MockEvent to keep track of the state and expose a method to show the current state.
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 &);
};
This is untested code. In real code, I'd wrap the CRITICAL_SECTION, too. Note that the result of IsSignaled may be obsolete the moment you get it, if another thread changes the state. I'm assuming this is for testing code that will check at a time when the state should be a certain way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With