Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Wie ist die Windows API Funktion EnterCriticalSection implementiert? (https://www.delphipraxis.net/170937-wie-ist-die-windows-api-funktion-entercriticalsection-implementiert.html)

QuickAndDirty 11. Okt 2012 10:05

Wie ist die Windows API Funktion EnterCriticalSection implementiert?
 
Hallo,
Es geht mir darum folgendes zu wissen. (Im zugehörigen MSDN Artikel habe ich nichts gefunden.)

Wie ist die API Funktion EnterCriticalSection implementiert?
A) Aktives Warten: Abfragen einer LockVariable in einer While schleife bis diese anzeigt, dass die Section zugänglich ist. Alle Threads die Warten verbrauchen CPU Zeit.

B) Semaphore:
Ein mit 1 initialisierte Semaphore.
Die Semaphore wird durch EnterCriticalSection decremtiert, wird die Semaphore dadurch negativ wird der Thread blockiert und in eine Warteschleife abgelegt, ist die Semaphore >=0 führt der Thread den Codeabschnitt aus .
Die Semaphore wird durch LeaveCtricalSection incremtiert. Wird sie dadurch <=0 kommt der nächste Thread aus der Warteschlange dran und wird aus der Warteschlange entfernt und aufgeweckt um den Code auszuführen. (Das bedeutet das ein Wert von 1 dazu führt das nichts weiter getan wird. sprich dann ist alles getan , fürs Erste.)
Nur die Vorgänge um das Prüfen und ändern der Semaphore werden über "Aktives Warten" geblockt die blockierten Threads in der Warteschlange selbst verbrauchen dann keine CPU Zeit.

C) Irgendwie anders?

himitsu 11. Okt 2012 11:51

AW: Wie ist die Windows API Funktion EnterCriticalSection implementiert?
 
Die arbeiten irgendwie mit Sperrvariablen, einem Event, Listen (wer grade per Enter anfragt), Speerzählern und sonstwas,
aber wozu muß man das unbedingt wissen?

Es funktioniert und ist sogar recht flott.

Hat mich auch gewundert, dachte das wäre langsamer und hab eine Zeit lang was Selbestgebasteltes verwendet. Über eine Schleife, 'nem winzigen Sleep (wegen der 100%-CPU) und das LOCK (Assembler), bzw. über die Interlocked-Funktionen.


Es ist auf jeden Fall nicht nur ein billiger Semaphore, denn das Sperren ist threadabhängig.
Der Thread, welcher das gesperrt hat, kann es recursiv beliebig oft "sperren".
(Ich hatte mal die Debuginfos der CS versucht auszuwerten, aber irgendwie scheint das intern nun anders zu funktionieren, als es die Debuginfos verraten.

PS: Es gibt hier irgendwo einen Thread von mir, wo ich mal versuchte ein Timeout für das ENTER zu implementieren, indem ich mich z.B. an das angeblich vorhandene Event hängen wollte.

QuickAndDirty 11. Okt 2012 12:02

AW: Wie ist die Windows API Funktion EnterCriticalSection implementiert?
 
Warum?
Arbeite an einer Anwendung mit möglicherweise hunderten von Threads, und die soll was beschleunigen, also sollte sie nicht die Prozessorzeit aufsaugen.

Das mit dem Event habe ich jetzt auch gelesen. Und zwar hier:
http://wuqingjun.wordpress.com/2010/...-in-user-mode/

Ich weiß zwar nicht was es in Windows bedeutet ein "Event" zu erzeugen aber das der Thread im "Kernelmode" keine CPU Zeit verbraucht ist schon mal gut.

Also wird es wohl so etwas ähnliches sein wie Variante B nur eben über ein "event" statt über ein Semaphore. Und mit "Kernelmode" statt "blocked".
(EDIT: hier noch was gefunden http://www.codeproject.com/Articles/...-Kernel-Object )

Also kann ich mit CritcalSection ganz gut weiter arbeiten.

Es ist schrecklich, ich habe mir gerade ALLES MÖGLICHE über Prozesse, Scheduling, Threads und Synchronisierung aus meinen alten Skripten noch mal durchgelesen...
Interessant was man so alles schon mal gewusst hat...

himitsu 11. Okt 2012 12:16

AW: Wie ist die Windows API Funktion EnterCriticalSection implementiert?
 
Wir verwenden auch nicht unbedingt wenige CS, aber von einer erwähnenswerten CPU-Auslastung, durch die CS, haben wir noch nichts bemerkt.

PS: TCriticalSection ist auch was Nettes. (kapselt die WinAPI-CS, hat kaum Overhead und vorallen in Bezug auf Multiplatform oder OOP ist es irgendwie schöner)

Mach dir doch einfach mal einen Thread
Delphi-Quellcode:
while not Terminated do begin
  CS.Enter;
  try
    Sleep(100);
  finally
    CS.Leave;
  end;
end;
und starte ihn ein paar Mal.

QuickAndDirty 11. Okt 2012 12:18

AW: Wie ist die Windows API Funktion EnterCriticalSection implementiert?
 
Zitat:

Zitat von himitsu (Beitrag 1186641)
Wir verwenden auch nicht unbedingt wenige CS, aber von einer erwähnenswerten CPU-Auslastung, durch die CS, haben wir noch nichts bemerkt.

PS: TCriticalSection ist auch was Nettes. (kapselt die WinAPI-CS, hat kaum Overhead und vorallen in Bezug auf Multiplatform oder OOP ist es irgendwie schöner)

Mach dir doch einfach mal einen Thread
Delphi-Quellcode:
while not Terminated do begin
  CS.Enter;
  try
    Sleep(100);
  finally
    CS.Leave;
  end;
end;
und starte ihn ein paar Mal.

Ich benutze TCriticalSection...aber ich wollte wissen wie die das machen... :) jetzt bin ich aber überzeugt !!!

mjustin 11. Okt 2012 14:06

AW: Wie ist die Windows API Funktion EnterCriticalSection implementiert?
 
Zitat:

Zitat von QuickAndDirty (Beitrag 1186638)
Arbeite an einer Anwendung mit möglicherweise hunderten von Threads, und die soll was beschleunigen, also sollte sie nicht die Prozessorzeit aufsaugen.

Je nachdem, worauf der Thread warten muss, ist neben der CriticalSection bei massiv parallelen Systemen auch immer mehr IOCP im Einsatz - hunderte oder tausende Threads sind damit "verlustlos" möglich. IOCP ist nicht nur auf Netzwerk / Socketprogrammierung beschränkt:

I/O completion port's advantages and disadvantages

Zitat:

I/O completion ports are awesome. There's no better word to describe them. If anything in Windows was done right, it's completion ports.

You can create some number of threads (does not really matter how many) and make them all block on one completion port until an event (either one you post manually, or an event from a timer or asynchronous I/O, or whatever) arrives. Then the completion port will wake one thread to handle the event, up to the limit that you specified. If you didn't specify anything, it will assume "up to number of CPU cores", which is really nice.
-> man kann eine praktisch unbegrenzte Anzahl Threads durch einen completion port blockieren lassen, bis ein Event eintrifft (entweder ein selbsterzeugtes oder ein Timer-Event oder ein asynchrones I/O Event). Dann wird der Completion Port einen Thread aufwecken, oder mehr (Vorgabe: so viele wie es CPU Kerne gibt).

(Es gibt IOCP API Implementierungen auch für Delphi als open source).

Is there a I/O completion port based component for Delphi?

JamesTKirk 13. Okt 2012 10:56

AW: Wie ist die Windows API Funktion EnterCriticalSection implementiert?
 
Zitat:

Zitat von QuickAndDirty (Beitrag 1186622)
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

dummzeuch 13. Okt 2012 16:15

AW: Wie ist die Windows API Funktion EnterCriticalSection implementiert?
 
Eventuell hilfreich:

http://delphitools.info/2011/11/30/f...iticalsection/

Ich weiss nicht, ob das in neueren Delphi-Versionen gefixt ist, aber in Delphi 2007 existiert das Problem. Deshalb habe ich mir eine eigene von TCtiticalSection abgeleitete Klasse geschrieben.

https://svn.code.sf.net/p/dzlib/code...calSection.pas

QuickAndDirty 15. Okt 2012 14:53

AW: Wie ist die Windows API Funktion EnterCriticalSection implementiert?
 
Zitat:

Zitat von dummzeuch (Beitrag 1186903)
Eventuell hilfreich:

http://delphitools.info/2011/11/30/f...iticalsection/

Ich weiss nicht, ob das in neueren Delphi-Versionen gefixt ist, aber in Delphi 2007 existiert das Problem. Deshalb habe ich mir eine eigene von TCtiticalSection abgeleitete Klasse geschrieben.

https://svn.code.sf.net/p/dzlib/code...calSection.pas


Das ist nicht deren ernst?

Ich setze Delphi2007 ein. also muss ich mir jetzt 'ne "größere" CS bauen oder in großen Objekten TRTLCriticalsection nutzen?


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:34 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz