Hallo,
Es geht mir darum folgendes zu wissen. (Im zugehörigen
MSDN Artikel habe ich nichts gefunden.)
Wie ist die
API Funktion EnterCriticalSection implementiert?
Für solche Fragen finde ich immer den Quellcode von
ReactOS sehr hilfreich. Also stürzen wir uns doch mal mitten rein:
Die Funktion
EnterCriticalSection wird von der
kernel32.dll exportiert, also schauen wir doch im entsprechenden
Verzeichnis mal nach. Ok, seitdem die Entwickler da drin aufgeräumt haben findet man da nichts mehr so leicht, aber versuchen wir es einfach mal damit mit
grep sämtliche Dateien zu durchsuchen. Dabei finden wir dann heraus, dass
EnterCriticalSection gar nicht selbst in der
kernel32.dll implementiert ist, sondern kurzerhand nach
RtlEnterCriticalSection in der
ntdll.dll geforwarded ist (sieht man, wenn man in der
kernel32.spec Datei nach der Funktion sucht).
Also gehen wir zur
ntdll. Hier ist jetzt leider eine kleine Gemeinheit, da die Funktion in der statisch gelinkten
RTL Bibilothek, statt der
ntdll selbst zu finden ist. Diese befindet sich
hier. Dort sieht man dann auch relativ schnell eine
critical.c-Datei, welche den Code für die kritischen Abschnitte enthält.
Schauen wir uns den Code also mal an. Zuerst wird versucht den
LockCount der nach außen hin nicht sichtbaren CriticalSection Struktur per
InterlockedIncrement zu erhöhen. War der Count vorher 0, so hat kein Thread die Section bisher betreten und der aktuelle Thread kann sie in Besitz nehmen. Andernfalls wird überprüft, falls der aktuelle Thread sie bereits betreten hat, dann muss natürlich nicht gewartet werden, damit ein Thread nicht sich selbst blockieren kann. Ansonsten hat ein anderer Thread den Lock und es muss mit Hilfe der privaten Funktion
RtlpWaitForCriticalSection darauf gewartet werden, dass der aktuelle Thread drankommt.
Gehen wir nun also zu dieser Wartefunktion weiter. Im Anfangscode bis zur
for-Schleife halten wir mal fest, dass es anscheinend einen Timeout für's Warten gibt (dessen Konfigurierbarkeit in ReactOS noch nicht voll implementiert ist). Innerhalb der
for-Schleife wird dann auf ein Ereignis gewartet, das Teil der Struktur der CriticalSection ist. Schlägt der Timeout einmal an, so gibt es noch eine zweite Chance das Lock zu bekommen ansonsten wird eine
Possible deadlock Exception ausgelöst. Das Ereignis wird übrigens innerhalb von
RtlpUnWaitCriticalSection gesetzt, welche von
RtlLeaveCriticalSection aufgerufen wird.
Man sieht also, dass die CriticalSection mit Hilfe eines Events gelöst ist. Durch
NtWaitForSingleObject wird dann (hoffentlich) auch dafür gesorgt, dass nur einer der wartenden Threads dann die Chance bekommt den kritischen Bereich zu betreten. Aber das behalten wir uns für einen anderen Ausflug in der Welt der NT
API vor
Gruß,
Sven