2016-06-12 4 views
0

Win 7, x64, Visual Studio Community 2015, C++Win32 События - Мне нужно, чтобы получить уведомление, когда событие очищается

У меня есть поток, который мне нужно сделать паузу/возобновлять или прекратить, что я в настоящее время сделать с событиями «запустить» или «убить» вручную. Цикл в потоке приостанавливается каждый раз на 5000 мс.

Моя цель состоит в том, чтобы иметь возможность прекратить ждать или убить нить, находясь в середине ожидания.

Проблема заключается в том, как я ее настроил, мне нужно получить уведомление, когда событие «запустить» переходит в состояние без сигнализации, но нет способа сделать это, если я не создаю событие с перевернутая полярность, но это похоже на клочок. Короче говоря, мне нужен чувствительный к уровню сигнал, а не чувствительный к регистру.

Возможно, событие должно просто переключать состояние запуска?

Это функция потока:

DWORD WINAPI DAQ::_fakeOutFn(void *param) { 
    DAQ *pThis = (DAQ *)param; 
    const DWORD timeout = 5000; 

    bool running = false; 
    HANDLE handles[] = { pThis->hFakeTaskRunningEvent, pThis->hFakeTaskKillEvent }; 

    do { 
     DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE); 
     switch (result) { 
     case WAIT_OBJECT_0: // Run started or continued 
      running = true; 
      pThis->outputIndex++; 
      if (pThis->outputIndex >= pThis->numSamples) 
       pThis->outputIndex = 0; 
      // Wait here 
      // Not sure how to cancel this if the TaskRunningEvent goes false during the wait 
      DWORD result2 = WaitForMultipleObjects(2, handles, FALSE, timeout); 
      // Check result2, and 'continue' the loop if hFakeTaskRunningEvent went to NON-SIGNALLED state 
      break; 
     case WAIT_OBJECT_0 + 1: // Kill requested 
      running = false; 
      break; 
     default: 
      _ASSERT_EXPR(FALSE, L"Wait error"); 
      break; 
     } 
    } while (running); 
    return 0; 
} 
+0

Здесь может быть улучшена переменная состояния. –

ответ

0

Используйте отдельные события для бега и резюме состояния. Затем вы можете сбросить событие возобновления, чтобы приостановить, и сигнализировать о возобновлении события. Рабочее событие должно использоваться, чтобы сообщить поток, когда он должен работать, а не когда он должен приостановить эту работу в течение определенного периода времени.

DWORD WINAPI DAQ::_fakeOutFn(void *param) 
{ 
    DAQ *pThis = (DAQ *)param; 

    bool running = false; 
    HANDLE handles[] = { pThis->hFakeTaskRunningEvent, pThis->hFakeTaskKillEvent }; 

    do 
    { 
     DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE); 
     switch (result) 
     { 
      case WAIT_OBJECT_0: // Run started 
      { 
       running = true; 
       pThis->outputIndex++; 
       if (pThis->outputIndex >= pThis->numSamples) 
        pThis->outputIndex = 0; 

       // check for pause here 
       HANDLE handles2[] = { pThis->hFakeTaskResumeEvent, pThis->hFakeTaskKillEvent }; 
       DWORD result2 = WaitForMultipleObjects(2, handles2, FALSE, INFINITE); 
       switch (result2) 
       { 
        case WAIT_OBJECT_0; 
         break; 

        case WAIT_OBJECT_0 + 1: // Kill requested 
         running = false; 
         break; 

        default: 
         _ASSERT_EXPR(FALSE, L"Wait error"); 
         break; 
       } 

       if (!running) break; 

       // continue working... 

       break; 
      } 

      case WAIT_OBJECT_0 + 1: // Kill requested 
       running = false; 
       break; 

      default: 
       _ASSERT_EXPR(FALSE, L"Wait error"); 
       break; 
     } 
    } 
    while (running); 

    return 0; 
} 
0

здесь я бы использовать не событие, но очереди APc на эту тему с «командой» (пуск, пауза, выход). однако нужно знать больше о задаче, для выбора лучшего решения. вы пишете услугу?

struct DAQ 
{ 
    HANDLE _hEvent; 

    enum STATE { 
     running, 
     paused, 
     exit 
    } _state; 

    DAQ() 
    { 
     _hEvent = 0; 
    } 

    ~DAQ() 
    { 
     if (_hEvent) 
     { 
      ZwClose(_hEvent); 
     } 
    } 

    NTSTATUS Init() 
    { 
     return ZwCreateEvent(&_hEvent, EVENT_ALL_ACCESS, 0, NotificationEvent, FALSE); 
    } 

    void Close() 
    { 
     if (HANDLE hEvent = InterlockedExchangePointer(&_hEvent, 0)) 
     { 
      ZwClose(hEvent); 
     } 
    } 

    DWORD fakeOutFn() 
    { 
     DbgPrint("running\n"); 
     _state = running; 
     ZwSetEvent(_hEvent, 0); 
     static LARGE_INTEGER Interval = { 0, MINLONG }; 
     do ; while (0 <= ZwDelayExecution(TRUE, &Interval) && _state != exit); 

     DbgPrint("exit\n"); 
     return 0; 
    } 

    static DWORD WINAPI _fakeOutFn(PVOID pThis) 
    { 
     return ((DAQ*)pThis)->fakeOutFn(); 
    } 

    void OnApc(STATE state) 
    { 
     _state = state; 

     static PCSTR stateName[] = { "running", "paused" }; 

     if (state < RTL_NUMBER_OF(stateName)) 
     { 
      DbgPrint("%s\n", stateName[state]); 
     } 
    } 

    static void WINAPI _OnApc(PVOID pThis, PVOID state, PVOID) 
    { 
     ((DAQ*)pThis)->OnApc((STATE)(ULONG_PTR)state); 
    } 
}; 

void test() 
{ 
    DAQ d; 
    if (0 <= d.Init()) 
    { 
     if (HANDLE hThread = CreateThread(0, 0, DAQ::_fakeOutFn, &d, 0, 0)) 
     { 
      if (STATUS_SUCCESS == ZwWaitForSingleObject(d._hEvent, FALSE, 0))// need for not QueueApc too early. in case ServiceMain this event not need 
      { 
       d.Close(); 
       int n = 5; 
       do 
       { 
        DAQ::STATE state; 
        if (--n) 
        { 
         state = (n & 1) != 0 ? DAQ::running : DAQ::paused; 
        } 
        else 
        { 
         state = DAQ::exit; 
        } 
        ZwQueueApcThread(hThread, DAQ::_OnApc, &d, (PVOID)state, 0); 
       } while (n); 
      } 
      ZwWaitForSingleObject(hThread, FALSE, 0); 
      ZwClose(hThread); 
     } 
    } 
} 
Смежные вопросы