Как определить сигнальное состояние Win32 Event? - PullRequest
11 голосов
/ 09 мая 2011

У меня есть объект события авто-сброса, созданный следующим образом:

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

Ответы [ 2 ]

3 голосов
/ 13 мая 2011

Я не вижу простого способа сделать это.Вы можете «смоделировать» событие в целях тестирования.

Обернуть событие в объект 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 может устареть в тот момент, когда вы его получите, если другой поток изменяет состояние.Я предполагаю, что это для тестирования кода, который будет проверять в то время, когда состояние должно быть определенным образом.

3 голосов
/ 13 мая 2011

Обновление:

Кофе включился, и я ошибся!

Использование WaitForSingleObject с таймаутом, равным нулю, для определения того, было ли сигнализировано событие, приведет к сбросу сигнала, если сигнализируется событие (и его событие AutoReset). В этом можно убедиться, просто дважды вызвав 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 равен нулю, функция не входит в состояние ожидания если критерии не выполнены; это всегда возвращается немедленно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...