2013-07-23 9 views
5

Utilizzo socket C# (che utilizzano IOCP per le richiamate). Voglio un metodo per determinare il tempo che la mia logica di elaborazione è in ritardo. C'è una chiamata API che potrebbe darmi la dimensione delle operazioni completate che non sono state elaborate dai callback?È possibile sapere quante operazioni completate non elaborate vengono accodate su un IOCP tramite una chiamata API?

Ho preso in considerazione l'utilizzo di un'operazione simile a un battito cardiaco che vorrei postare in coda e determinare se sono indietro per il tempo trascorso alla sua richiamata, ma preferirei un percorso più diretto se possibile (Plus I don ' t avere un facile accesso al comando IOCP che controlli .Net internals).

risposta

4

non tramite un API documentata ma si potrebbe provare questo ...

/* 
GetIocpQueueCount 

Description: 
Returns the number of queued IOCP work and I/O completion items. 

Remarks: 
Microsoft declined to implement the NtQueryIoCompletion routine 
for user mode. This function gets past that omission by calling 
the NTDLL.DLL function dynamically. 

Returns: 
Number of items in the queue at the instant this function was 
called, or -1 if an error occurred. Errors can be retrieved 
by calling GetLastError. 
*/ 
long GetIocpQueueCount() 
{ 
    long lQueueDepth = -1; 

    typedef DWORD (WINAPI *LPFNNTQUERYIOCOMPLETION)(HANDLE, int, PVOID, ULONG, PULONG); 

    static LPFNNTQUERYIOCOMPLETION pfnNtQueryIoCompletion = NULL; 

    if (MFTASKQUEUENOTCREATED != m_dwStatus) 
    { 
     DWORD rc = NO_ERROR; 

     /* need to load dynamically */ 

     if (NULL == pfnNtQueryIoCompletion) 
     { 
     /* Now dynamically obtain the undocumented NtQueryIoCompletion 
      * entry point from NTDLL.DLL 
      */ 

     HMODULE hmodDll = ::GetModuleHandleW(L"ntdll.dll"); 

     // NTDLL is always loaded, just get its handle 

     if (NULL != hmodDll) 
     { 
      pfnNtQueryIoCompletion = (LPFNNTQUERYIOCOMPLETION)::GetProcAddress(
       hmodDll, 
       "NtQueryIoCompletion"); // NB: ANSI 
     } 
     } 

     if (NULL != pfnNtQueryIoCompletion) 
     { 
     rc = (pfnNtQueryIoCompletion)(
      m_hIOCP, 
      0, 
      (PVOID)&lQueueDepth, 
      sizeof(lQueueDepth), 
      NULL); 
     } 
     else 
     { 
     rc = ERROR_NOT_FOUND; 
     } 
     ::SetLastError(rc); 
    } 
    return lQueueDepth; 
} 
+0

Questo è abbastanza pulito, ma .NET non espone il suo creato internamente 'm_hIOCP'. – dtb

+0

questo è fantastico! @dtb nessun problema, posso estrarlo con la riflessione. ma a prescindere, penso che l'uso di un battito cardiaco mi darà una visione più realistica di quanto io sia indietro. ma l'implementazione del battito cardiaco sarà ancora più fastidiosa di questo semplice metodo poiché non ho modo di implementare un gestore personalizzato sul threadpool IOCP .net. dovrei usare una connessione socket al mio server per implementare l'heartbeat. –

+0

Se è possibile estrarre l'handle con la riflessione, si prega di postare il codice da qualche parte. Ci sto provando da secoli. – dtb