2013-02-17 13 views
8

Vorrei compilare un elenco di tutte le possibili condizioni che rendono Monitor andare in modalità kernel/utilizzare l'oggetto di sincronizzazione del kernel.Quando esattamente .NET Monitor va in modalità kernel?

Il blocco di sincronizzazione ha un campo per fare riferimento all'oggetto del kernel quindi ho dedotto che lo lock passerà in modalità kernel qualche volta.

ho trovato questo: Lock (Monitor) internal implementation in .NET

ma ha troppe domande a cui rispondere e l'unica informazione utile è che il PO ha risposto alla sua stessa domanda, semplicemente affermando che il lock andrà alla modalità kernel qualche volta. Inoltre non ci sono collegamenti a nulla per supportare quella risposta.

La mia domanda è diversa - Voglio sapere quando esattamente lock andrà in modalità kernel (non se e non perché - quando).

io sono più interessato a sentir parlare di .NET 4 e 4,5 se non v'è alcuna differenza con le versioni precedenti

EDIT: Dal libro Richter: "Un blocco di sincronizzazione contiene campi per un oggetto del kernel, il possedere l'ID del thread, un conteggio della ricorsione e un conteggio thread in attesa. "

risposta

19

La maggior parte di questi tipi di domande può essere risolta osservando il codice sorgente CLR come disponibile tramite SSCLI20 distribution. Ormai è piuttosto datato, è .NET 2.0 vintage, ma molte delle funzionalità CLR di base non sono cambiate molto.

Il file del codice sorgente che si desidera esaminare è clr/src/vm/syncblk.cpp. Tre classi svolgono un ruolo in questo caso, AwareLock è l'implementazione del blocco di basso livello che si occupa dell'acquisizione del blocco, SyncBlock è la classe che implementa la coda dei thread in attesa di entrare in un blocco, CLREvent è il wrapper per la sincronizzazione del sistema operativo oggetto, quello che stai chiedendo.

Questo è il codice C++ e il livello di astrazione è piuttosto elevato, questo codice interagisce pesantemente con il garbage collector e c'è molto codice di test incluso. Quindi darò una breve descrizione del processo.

SyncBlock ha il membro m_Monitor che archivia l'istanza AwareLock. SyncBlock :: Enter() chiama direttamente AwareLock :: Enter(). Prima cerca di acquisire il blocco nel modo più economico possibile. Innanzitutto verifica se il thread possiede già il blocco e semplicemente incrementando il conteggio dei blocchi, se questo è il caso. Successivamente si utilizza FastInterlockCompareExchange(), una funzione interna molto simile a Interlocked.CompareExchange(). Se il blocco non viene conteso, questo succede molto rapidamente e Monitor.Enter() restituisce. In caso contrario, un altro thread possiede già il blocco, viene utilizzato AwareLock :: EnterEpilog. È necessario che lo scheduler dei thread del sistema operativo sia coinvolto in modo che venga utilizzato CLREvent.Viene creato dinamicamente se necessario e viene chiamato il suo metodo WaitOne(). Che comporterà una transizione del kernel.

Così sufficiente per rispondere alla tua domanda: la classe Monitor entra nella modalità kernel quando il blocco viene conteso e il thread deve attendere.

+0

grazie mille. soprattutto per il SSCLI - non sapevo che fosse disponibile pubblicamente. –

+3

Grazie per il commento che mi ha indirizzato a una parte rilevante nella sorgente CLR. Sono interessato in particolare alla spinning part: è comunemente richiesto Monitor sui primi spin prima di passare al kernel. E mi interessa come gira esattamente (numero di iterazioni, ...). Non riesco a vedere la rotazione nel percorso del codice che hai descritto, tuttavia, vedo la logica della rotazione in AwareLock :: Contention chiamata da AwareLock :: TryEnter. Ora sembra che questo si applica solo a TryEnter quando viene utilizzato il timeout, quindi suppongo che la rotazione non venga utilizzata quando si utilizza la parola chiave C# lock. Ho ragione? –

1

Dopo lo spinwait.

può esistere ulteriore intelligenza, ad esempio saltando lo spinwait su macchine single core poiché il blocco contestato poteva essere rilasciato solo dopo aver rilasciato il thread.

+0

Andrew Ho bisogno di avere tutti i passaggi in vista piana per vedere come questo risponde alla domanda. La tua risposta è come - quando le persone muoiono se colpite da un fulmine - quando sono morte. –

+0

@BoppityBop: Vai a prendere un aereo e una pista di atterraggio, poi discutiamo questo punto –

+0

Ya. Se vuoi qualcosa di più preciso, che ne dici di "alle 5: 04: 02.008"? Seriamente, una risposta assoluta è inutile, e una risposta relativa varia. L'unica cosa rimasta è una risposta logica. Dopo aver completato il passaggio precedente, la tua domanda non ha un punto che cerchi. Perché ti interessi? Se lo hai fornito, potremmo essere in grado di fornire una risposta più utile. –

2

Quando il blocco è fortemente conteso.

Se il blocco è leggermente sostenuto, c'è uno spinlock CPU veloce per attendere che il blocco di essere di nuovo libero, ma se questo non attende abbastanza a lungo per il blocco di essere liberi, il filo si blocca attesa sul mutex, che implica una chiamata in modalità kernel per sospendere il thread e altri tipi di gestione.

Problemi correlati