如何确定Win32事件的信号状态?

Rod*_*ddy 12 c++ events winapi

我有一个自动重置事件对象,如下所示:

handle = CreateEvent(NULL, true, false, NULL);
Run Code Online (Sandbox Code Playgroud)

...(和某些单元测试目的)我想检查它是否在某一点发出信号.我知道使用事件的"正确"方式 - 这纯粹是为了诊断工具.

对于手动重置事件,我可以使用......

bool signalled = WaitForSingleObjectEx(handle, 0, true) != WAIT_TIMEOUT;
Run Code Online (Sandbox Code Playgroud)

...但是对于具有重置它们的副作用的自动重置事件.我想我可以试试这个,但我觉得应该有一个不那么危险的方式......?

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; 
}
Run Code Online (Sandbox Code Playgroud)

Iva*_*non 5

更新:

咖啡已经开始了,我错了!

使用超时为零的 WaitForSingleObject 来确定事件是否已发出信号,如果事件已发出信号(及其自动重置事件),将导致信号被清除。您可以通过简单地连续调用 WaitForSingleObject 两次来验证这一点。


在重置为自动重置而初始化的事件之前,必须释放等待线程。

http://msdn.microsoft.com/en-us/library/ms682396(VS.85).aspx

当您以零超时调用 WaitForSingleObjectEx 时,您的线程不会成为服务员。

http://msdn.microsoft.com/en-us/library/ms687036(VS.85).aspx

如果 dwMilliseconds 为零,则如果不满足条件,函数不会进入等待状态;它总是立即返回。


Adr*_*thy 4

我没有看到一个简单的方法来做到这一点。您可以出于测试目的“模拟”该事件。

将事件包装在 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 &);
};
Run Code Online (Sandbox Code Playgroud)

然后,您将需要使用某种引用计数指针,该指针可以像原始句柄一样传递和复制:

typedef std::tr1::shared_ptr<MockEvent> MockEventPtr;
Run Code Online (Sandbox Code Playgroud)

将使用原始 HANDLE 的所有代码替换为 MockEventPtr。

// Original code:
HANDLE hEvent = CreateEvent(NULL, true, false, NULL);
// Becomes:
MockEventPtr pEvent(new MockEvent);

// Original code:
SetEvent(hEvent);
// Becomes:
pEvent->Set();
Run Code Online (Sandbox Code Playgroud)

等等。

现在,对于您的诊断工具,您可以扩展 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 &);
};
Run Code Online (Sandbox Code Playgroud)

这是未经测试的代码。在实际代码中,我也会包装 CRITICAL_SECTION。请注意,如果另一个线程更改状态,IsSignaled 的结果可能在您获得它时就已过时。我假设这是为了测试代码,该代码将在状态应该以某种方式进行检查时进行检查。