3 Stimmen

Kritische Abschnitte, die auf Posix drehen?

Die Windows-API bietet kritische Abschnitte, in denen ein wartender Thread eine begrenzte Anzahl von Malen rotiert, bevor ein Kontextwechsel erfolgt, jedoch nur auf einem Multiprozessorsystem. Diese werden mit InitializeCriticalSectionAndSpinCount implementiert. (Siehe http://msdn.microsoft.com/de-de/library/ms682530.aspx.) Dies ist effizient, wenn Sie einen kritischen Abschnitt haben, der oft nur für kurze Zeit gesperrt wird und daher der Konflikt nicht sofort einen Kontextwechsel auslösen sollte. Zwei verwandte Fragen:

  1. Für eine High-Level, plattformunabhängige Threading-Bibliothek oder eine Implementierung eines synchronized-Blocks ist es eine gute Standardeinstellung, eine geringe Menge an Rotation vor einem Kontextwechsel auszulösen?
  2. Was ist das Äquivalent zu InitializeCriticalSectionAndSpinCount auf anderen Betriebssystemen, insbesondere Posix?

Bearbeiten: Natürlich ist keine Rotationsanzahl für alle Fälle optimal. Mich interessiert nur, ob die Verwendung einer nichtnull Rotationsanzahl standardmäßig besser ist als keine zu verwenden.

4voto

Aidan Cully Punkte 5297

Meine Meinung ist, dass die optimale "Spin-Zählung" für die beste Anwendungsleistung zu sehr von der Hardware abhängt, um ein wichtiger Bestandteil einer plattformübergreifenden API zu sein, und Sie sollten wahrscheinlich einfach Mutexe verwenden (in posix, pthread_mutex_init / destroy / lock / trylock) oder Spin-Locks (pthread_spin_init / destroy / lock / trylock). Die Begründung folgt.

Was ist der Sinn der Spin-Zählung? Grundsätzlich, wenn der Lock-Besitzer gleichzeitig mit dem Thread läuft, der versucht, den Lock zu erwerben, könnte der Lock-Besitzer den Lock schnell genug freigeben, dass der Aufrufer von EnterCriticalSection die CPU-Kontrolle beim Erlangen des Locks nicht aufgeben müsste, was die Leistung dieses Threads verbessern würde und den Overhead eines Kontextwechsels vermeiden würde. Zwei Dinge:

1: Offensichtlich hängt dies davon ab, dass der Lock-Besitzer parallel zum Thread läuft, der versucht, den Lock zu erwerben. Dies ist auf einem einzigen Ausführungskern unmöglich, was höchstwahrscheinlich der Grund ist, warum Microsoft die Zählung in solchen Umgebungen als 0 behandelt. Auch bei mehreren Kernen ist es durchaus möglich, dass der Lock-Besitzer nicht läuft, wenn ein anderer Thread versucht, den Lock zu erwerben, und in solchen Fällen ist die optimale Spin-Zählung (für diesen Versuch) immer noch 0.

2: Bei gleichzeitiger Ausführung hängt die optimale Spin-Zählung immer noch von der Hardware ab. Unterschiedliche Prozessoren benötigen unterschiedliche Zeiten für ähnliche Operationen. Sie haben unterschiedliche Befehlssätze (die ARM, mit der ich am meisten arbeite, hat keinen Integer-Divisionsbefehl), unterschiedliche Cache-Größen, das Betriebssystem wird verschiedene Seiten im Speicher haben... Das Dekrementieren der Spin-Zählung kann auf einer Load-Store-Architektur eine unterschiedliche Zeit in Anspruch nehmen als auf einer Architektur, bei der arithmetische Befehle direkt auf den Speicher zugreifen können. Selbst auf demselben Prozessor wird dieselbe Aufgabe je nach (mindestens) Inhalt und Organisation des Speichercaches unterschiedliche Zeit in Anspruch nehmen.

Wenn die optimale Spin-Zählung bei gleichzeitiger Ausführung unendlich ist, dann sollten die pthread_spin_*-Funktionen das tun, was Sie möchten. Wenn sie es nicht ist, verwenden Sie die pthread_mutex_*-Funktionen.

1 Stimmen

Ich stimme mit Ihnen überein, dass das Zählen von Spins nie eine gute Idee war und hoffentlich in neuen CPU-Generationen mit wesentlich effizienterer Hardware und einem vom Scheduler unterstützten Blockieren/Entblockieren entfernt wird. Übrigens ist die neue schlanke Lese-/Schreibimplementierung in Vista/Windows7 schneller als kritische Abschnitte, daher wird empfohlen, diese anstelle von Spin-Count/kritischen Abschnitten zu verwenden.

0voto

chill Punkte 16115

Für eine plattformübergreifende, hochrangige Thread-Bibliothek oder eine Implementierung eines synchronisierten Blocks ist es eine gute Standardoption, eine kurze Zeit zu warten, bevor ein Kontextwechsel ausgelöst wird?

Man würde meinen. Vor vielen Monden implementierte Solaris 2.x adaptive Sperren, die genau das taten - eine Weile zu warten, wenn das Mutex von einem Thread auf einem anderen Prozessor ausgeführt wird, oder anderweitig zu blockieren.

Offensichtlich macht es keinen Sinn, auf Ein-Prozessor-Systemen zu warten.

0 Stimmen

Das Ausführen auf Einzel-CPU-Systemen ist erforderlich, weil Unterbrechungen immer ein Teil des Bildes sind.

0 Stimmen

Im Kontext einer "hochstufigen, plattformübergreifenden Bibliothek oder Implementierung eines synchronisierten Blocks" sind Interrupts kein Teil des Bildes.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X