2016-06-12 4 views
0

Win 7 mal 64, Visual Studio Gemeinschaft 2015, C++Win32 Events - Ich muss benachrichtigt werden, wenn das Ereignis gelöscht wird

Ich habe einen Thread, die ich brauche/unpause zu pausieren oder beenden, die ich zur Zeit tun mit manuelles Zurücksetzen der Ereignisse "run" oder "kill" Die Schleife im Thread pausiert jedes Mal für 5000ms.

Mein Ziel ist es, in der Mitte des Wartens warten zu können oder den Thread zu beenden.

Das Problem ist die Art, wie ich es derzeit eingerichtet habe, ich muss benachrichtigt werden, wenn das Ereignis "run" in den nicht signalisierten Zustand geht, aber es gibt keine Möglichkeit, dies zu tun, es sei denn, ich erstelle ein Ereignis mit die umgekehrte Polarität, aber das scheint wie ein Klud. Kurz gesagt, ich brauche ein pegelempfindliches Signal, nicht kantenempfindlich.

Vielleicht sollte das Ereignis nur den Laufstatus wechseln?

Dies ist die Thread-Funktion:

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

Eine Zustandsvariable funktioniert hier möglicherweise besser. –

Antwort

0

Verwenden Sie separate Ereignisse für den Betrieb und die Wiederaufnahme Staaten. Dann können Sie das Wiederaufnahmeereignis auf Pause setzen und das Fortsetzen des Ereignisses signalisieren. Das running -Ereignis sollte verwendet werden, um den Thread wissen zu lassen, wann es Arbeit zu tun hat, und nicht, wann er diese Arbeit für eine gewisse Zeit pausieren sollte.

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

hier ich nicht Ereignisse verwenden, sondern mit 'Befehl' (run, Pause, Ausgang) auf diesen Thread Apc Warteschlange. Sie müssen jedoch mehr über die Aufgabe wissen, um die beste Lösung zu finden. schreibst du service?

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); 
     } 
    } 
} 
Verwandte Themen