2012-10-01 16 views
7

sto cercando di aggiungere un po 'di debug il controllo di un codice di sblocco CRITICAL_SECTION, e ho provato quanto segue:Perché il membro OwningThread di CRITICAL_SECTION di tipo HANDLE, quando sta denotando l'ID del thread?

... 
    if (m_pCritSect) { 
    ASSERT(m_pCritSect->OwningThread == GetCurrentThreadId()); 
    LeaveCriticalSection(m_pCritSect); 
    } 
} 

Da debug CRITICAL_SECTIONS (con VS 2005, per lo più su WindowsXP) I "so" che il valore di OwningThread (membro della struttura RTL_CRITICAL_SECTION definita in winnt.h) è il valore di ID del thread che contiene il blocco.

Tuttavia infilare ID sono rappresentati da DWORD (typedef per unsigned long) valori mentre la variabile è di tipo HANDLE (typedef per void*) richiedono un reinterpret_cast per l'utilizzo del HandleToULong macro dal basetsd.h per il codice suddetto funzioni.

Anche il MSDN docs Stato:

Quando il primo thread chiama la routine EnterCriticalSection, (...) OwningThread diventa l'ID del thread del chiamante.

Quindi perché sulla terra è definito come HANDLE?


Modifica nota: ho trovato a statement dove un manifesto suggerisce che la maniglia/DWORD-Id mancata corrispondenza è una certa misfeature nota di alcuni interne di Windows. Quindi forse questo è il caso anche qui:

GetCurrentThreadId restituisce un valore DWORD, che mando fino al kernel in un messaggio . PsLookupThreadByThreadId prende l'ID del thread in un manico, ... ...

Si tratta di un bug noto API di Windows ("conosciuto" in quanto ho parlato con il relativo DEV filtro direttore circa questo problema, come si vede in Filtro Manager anche a causa del problema dell'API I/O Manager. Finché l'utente non ha più di mezzo miliardo di thread e processi (essi utilizzano utilizzano una singola tabella di handle condivisa), si andrà bene . Forse per il momento questo è un vero problema, eseguiremo qualcosa di diverso. [RE: ThreadId to HANDLE per 64 bit?, 08 ago 08 14:21, Tony Mason]

+1

In ogni caso reinterpret_cast è eccessivo. Farebbe un static_cast Sia HANDLE che DWORD sono tipi interi. –

+0

@ArmenTsirunyan - NO, in VS2005 non è possibile utilizzare un static_cast per trasmettere un HANDLE a un DWORD: 'errore C2440: 'static_cast': impossibile convertire da 'HANDLE' a 'DWORD'' –

+0

Questo è strano. Potresti dirmi per cosa sono i typedef? –

risposta

8

Qualsiasi identificatore nel SDK il cui nome inizia con RTL o Rtl è un codice o le dichiarazioni che fanno parte del runtime strato, la colla che sposa il ben documentato Winapi con l'API del sistema operativo nativo non documentato. Il winapi è scolpito nella pietra, il sistema operativo nativo cambia pesantemente con ogni versione di Windows. Inevitabilmente, anche la colla cambia.

Il winapi è il livello documentato, il sistema operativo nativo non è documentato. Anche il livello di runtime non era documentato, ma nel tempo ne sono state rivelate parti. O perché torna a riempire una funzionalità mancante nel winapi. O, in questo caso, perché è davvero utile per risolvere i problemi. Un problema fondamentale nel farlo è che, una volta rivelata una dichiarazione, Microsoft non potrà mai più cambiarla. Perché così facendo si interrompono i programmi esistenti, un grande onere per i propri clienti.

Quindi, sicuramente, il campo ThreadOwner una volta ha mantenuto l'handle del thread in una versione precedente di Windows. Nota come LockSemaphore sia fuorviante, in realtà è un evento di reset automatico. Troppo tardi per sistemarlo, il gatto è fuori dalla borsa.

4

Credo che la ragione principale sia che si tratta di un dettaglio di implementazione. Non sarei sorpreso se in una sola volta nella storia fosse davvero una maniglia o qualcosa del genere.

Inoltre, suggerisco caldamente di non utilizzare i membri interni nel codice di produzione e I am not alone. Se si guarda da vicino, le API di sincronizzazione usano CRITICAL_SECTION che non troverete documentato come una struttura in MSDN, e non RTL_CRITICAL_SECTION (che è typedef'ed a CRITICAL_SECTION)

Il valore che viene memorizzato in OwningThread membro è preso da CLIENT_ID parte di Thread Information Block.In CLIENT_ID come modellata come PVOID che probabilmente il motivo per cui è modellata nello stesso modo entro CRITICAL_SECTION:

typedef struct _CLIENT_ID 
{ 
    PVOID UniqueProcess; 
    PVOID UniqueThread; 
} CLIENT_ID, *PCLIENT_ID; 
+0

Ho fornito un collegamento MSDN che attraversa questa struttura (concesso è nella sezione * Advanced Debugging Tasks *), quindi penso che sia abbastanza corretto usare questo * nel codice di controllo di debug *. –

+0

Non verrà ancora generato se la struttura cambia, e inoltre non considero il codice di produzione reale del codice ASSERT, poiché non viene distribuito all'utente finale (ad esempio nella versione di rilascio) –