Frage

Ich war eine Multi-Threaded-Anwendung debuggen und fand die interne Struktur von CRITICAL_SECTION. Ich fand Daten Mitglied LockSemaphore von CRITICAL_SECTION interessant.

Es sieht aus wie LockSemaphore ein Auto-Reset-Ereignis ist (kein Semaphore wie der Name schon sagt) und das Betriebssystem schafft dieses Ereignis still, wenn erstmals ein Thread auf Critcal Section wartet, die von einem anderen Thread gesperrt ist.

Nun, ich frage mich, ist Critical Section schneller immer? Ereignis ist ein Kernel-Objekt und jeder kritischer Abschnitt Objekt mit Ereignis-Objekt zugeordnet ist dann, wie Critical Section schneller im Vergleich zu anderen Kernel-Objekten wie Mutex werden kann? Auch, wie sie internes Ereignisobjekt wirkt tatsächlich die Leistung von kritischem Abschnitt?

Hier ist die Struktur des CRITICAL_SECTION:

struct RTL_CRITICAL_SECTION
{
    PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
    LONG LockCount;
    LONG RecursionCount;
    HANDLE OwningThread;
    HANDLE LockSemaphore;
    ULONG_PTR SpinCount;
};
War es hilfreich?

Lösung

Wenn sie sagen, dass ein kritischer Abschnitt „schnell“ ist, sie bedeuten „ist es billig ein zu erwerben, wenn sie nicht bereits von einem anderen Thread gesperrt ist“.

[Beachten Sie, dass, wenn es ist bereits von einem anderen Thread gesperrt, dann spielt es keine Rolle fast so viel, wie schnell es ist.]

Der Grund, warum es schnell ist, weil, bevor sie in den Kern geht es um das Äquivalent von InterlockedIncrement auf einem dieser LONG Feld verwendet (vielleicht auf dem der LockCount Feld), und wenn es gelingt, dann hält es das Schloss aquired ohne gegangen in den Kernel.

Die InterlockedIncrement API Ich denke, im User-Modus als „LOCK INC“ opcode ... in anderen Worten implementiert Sie, ohne dabei jeden Ring Übergang in den Kernel überhaupt einen unbestrittenen kritischen Abschnitt erwerben können.

Andere Tipps

Leistung Arbeit, fallen einige Dinge in die „immer“ Kategorie :) Wenn Sie etwas selbst implementieren, dass ähnlich zu einem OS-kritischen Abschnitt mit anderen Primitiven dann Chancen sind, dass in den meisten Fällen langsamer sein wird.

Der beste Weg, um Ihre Frage zu beantworten, ist mit Performance-Messungen. Wie OS Objekte ist jedoch sehr auf dem Szenario abhängig. Zum Beispiel sind kritische Abschnitte allgemein als ‚schnell‘, wenn Anstoß ist gering. Sie sind auch schnell, wenn die Sperrzeit geringer ist als die Spin Zählzeit betrachtet.

Das Wichtigste, um zu bestimmen, ob Konflikte auf einem kritischen Abschnitt der erste Auftrag Faktor in Ihrer Anwendung zu begrenzen ist. Wenn nicht, dann verwenden Sie einfach einen kritischen Abschnitt normaly und arbeiten auf Ihre Anwendungen primären Engpass (oder Hälse).

Wenn kritische Abschnitt Leistung kritisch ist, dann können Sie prüfen, die folgend.

  1. setzen Sie vorsichtig die Spin-Lock-Zählung für ‚heiße‘ kritische Abschnitte. Wenn die Leistung an erster Stelle steht, dann ist hier die Arbeit ist es wert. Denken Sie daran, während der Spin-Lock den Benutzermodus tut vermeiden Übergang zum Kernel, es CPU-Zeit mit rasender Geschwindigkeit verbraucht - während des Drehens, sonst nichts, dass die CPU-Zeit verwenden wird. Wenn eine Sperre für lange genug gehalten wird, dann wird der Spinnfaden tatsächlichen Block wird, dass die CPU-Freisetzung zu anderer Arbeit zu tun.
  2. Wenn Sie einen Leser / Schreiber Muster haben, dann sollten Sie die Schlanke Reader / Writer (SRW) sperrt . Der Nachteil hier ist, dass sie nur verfügbar sind, auf Vista und Windows Server 2008 und später Produkte.
  3. Sie können möglicherweise Bedingungsvariablen mit dem kritischen Abschnitt Polling und Konflikte zu minimieren, Fäden nur Aufwachen, wenn nötig. Auch diese sind auf Vista und Windows Server 2008 und später Produkten unterstützt.
  4. Erwägen Sie Verriegelt einfach verkettete Listen ( SLIST) - das ist effizient und ‚frei sperren‘. Noch besser ist, werden sie auf XP und Windows Server 2003 unterstützten und später Produkte.
  5. überprüfen Sie Ihre Code -. Sie in der Lage sein, können durch Refactoring einiger Codes ein ‚heißes‘ Schloss aufzubrechen und mit einer Verriegelungsfunktion oder SLIST zur Synchronisation und Kommunikation

Zusammengefasst - Tuning-Szenarien, die Sperr-Konflikt haben kann schwierig sein (aber interessant!) Arbeit. Konzentrieren Sie sich auf die Messung Ihrer Anwendungen Leistung und das Verständnis, wo Ihre heißen Pfade sind. Die xperf Werkzeuge in der Windows-Performance Tool Kit hier ist dein Freund :) wir soeben Version 4.5 in dem Microsoft Windows SDK für Windows 7 und .NET Framework 3.5 SP1 ( ISO ist hier , Web-Installer hier ). Sie können das Forum für die xperf Tools finden hier . V4.5 unterstützt Win7, Vista, Windows Server 2008 -. Alle Versionen

CriticalSections ist schneller, aber InterlockedIncrement / InterlockedDecrement ist. Sehen Sie diese Implementierung usage sample LightweightLock vollständige Kopie .

Die CriticalSections eine kurze Zeit (wenige ms) Spin und Kontrolle halten, wenn die Sperre frei ist. Nach dem Spin ‚Timeout‘ zählt, wird es dann an dem Kernel Ereignis zurückgreifen. So in dem Fall, in dem der Inhaber der Sperre schnell steigt aus, man muss nie den teueren Übergang Code zum Kernel.

EDIT: Went und fand einige Kommentare in meinem Code: anscheinend der MS Heap-Manager verwendet eine Spinzahl von 4000 (ganzzahligen Inkrementen, nicht ms)

Hier ist ein Weg, um es zu betrachten:

Wenn es keine Konkurrenz gibt, dann ist der Spin-Lock ist wirklich schnell im Vergleich zu gehen Modus für einen Mutex auf Kernel.

Wenn es Streit, ein Critical ist etwas teurer als ein Mutex direkt mit (wegen der zusätzlichen Arbeit, die spinlock Zustand zu erfassen).

So ist es zu einem gewichteten Durchschnitt läuft darauf hinaus, wobei die Gewichte hängen von den Besonderheiten Ihres Nutzungsverhaltens. Davon abgesehen, wenn Sie wenig Konkurrenz haben, dann ein Critical großer Gewinn ist. Wenn auf der anderen Seite, Sie konsequent eine Menge Konkurrenz haben, dann würden Sie eine sehr kleine Strafe über mit einem Mutex direkt zu bezahlen sein. Aber in diesem Fall, was Sie durch den Wechsel zu einem Mutex gewinnen würden, ist klein, so dass Sie wahrscheinlich besser dran sein würden versuchen, den Streit zu reduzieren.

Kritische Abschnitt ist schneller als Mutex warum, weil kritische Abschnitt nicht ein Kernel-Objekt ist. Dies ist Teil des globalen Speichers des aktuellen Prozesses. Mutex tatsächlich wohnt in Kernel und die Schaffung von mutext Objekt erfordert einen Kernel-Schalter, aber im Fall von kritischem Abschnitt nicht. Obwohl kritische Abschnitt schnell ist, wird es ein Kernel-Schalter sein, während kritischen Abschnitt zu verwenden, wenn Threads Zustand warten werden. Dies liegt daran, Thread-Scheduling im Kernel-Seite geschieht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top