Warum sind Spin-Locks im Linux-Kernel-Design eine gute Wahl, anstatt etwas, das im Userland-Code häufiger vorkommt, wie Semaphor oder Mutex?

6

Ich verstehe, dass Spinlocks im Linux-Kernel-Design echte Verschwendung sind.

Ich würde gerne wissen, warum Spin-Locks im Linux-Kernel-Design eine gute Wahl sind, anstatt etwas, das im Userland-Code häufiger vorkommt, wie Semaphor oder Mutex.

Sen.
quelle
1
Spinlocks sind im Kernel-Code nicht immer eine Verschwendung. Dies wurde von @HandyGandy in Ihrer vorherigen Frage sehr gut erklärt .
Shawn J. Goff
@Shawn: Aber ich möchte es zu einer separaten Frage machen, wo ich klarere Antworten bekommen könnte.
Sen
2
Obwohl hier die Frage Sie fragen nicht identisch mit Ihrer vorherigen Frage, es hat von mehreren Personen auf dem vorherigen Thread beantwortet. Lesen Sie auch hier Kapitel 5 der Linux-Gerätetreiber , in dem dies erläutert wird.
Gilles 'SO - hör auf böse zu sein'
@ Gilles: Sicher .. Ich werde das tun .. Aber ich bevorzuge es, die Konzepte durch Diskussion zu verstehen, anstatt die Bücher zu lesen und zu absorbieren .. :-)
Sen

Antworten:

8

Die Wahl zwischen einem Spinlock und einem anderen Konstrukt, das den Aufrufer veranlasst, die Kontrolle über eine CPU zu blockieren und aufzugeben, hängt in hohem Maße von der Zeit ab, die für die Durchführung eines Kontextwechsels erforderlich ist (Register / Status im Sperrthread speichern und Register / Status wiederherstellen) in einem anderen Thread). Der Zeitaufwand und auch die Cache-Kosten hierfür können erheblich sein.

Wenn ein Spinlock verwendet wird, um den Zugriff auf Hardwareregister oder ähnliches zu schützen, bei dem ein anderer Thread, auf den zugegriffen wird, nur wenige Millisekunden oder weniger benötigt, bevor er die Sperre aufhebt, ist es viel besser, die CPU-Zeit zum Spinnen des Wartens zu nutzen anstatt den Kontext zu wechseln und weiterzumachen.

Richm
quelle
1
Wenn der blockierte Aufrufer keinen Kontextwechsel durchführt, wie kann dieser andere Thread die Sperre aufheben?
David Cary
1
Im Kernel kann der Spinlock nur von einer anderen CPU gehalten werden, nicht von einem anderen Thread. Daher können Sie warten, bis die andere CPU die Sperre aufhebt.
Tino
11

Da die Frage impliziert, dass Spinlocks eine "Verschwendung" sind, sollten Spinlocks nur kurz gehalten werden.

Spinlocks sind nicht die einzige Möglichkeit, mehrere Threads zu synchronisieren. Mutexe / Semaphore werden ebenso im Linux-Kernel verwendet wie andere Synchronisationsprimitive (z. B. Warteschlangen, Ereignisse).

Der Kernel muss sich jedoch mit Fällen befassen, die der Benutzerbereich nie sieht. Ein häufiger Fall sind Interrupt-Handler. Interrupt-Handler können unter Linux nicht neu geplant werden, müssen jedoch häufig ein Synchronisationsprimitiv verwenden (z. B. um ein Arbeitselement zu einer verknüpften Liste hinzuzufügen, das von einem anderen Thread weiter verarbeitet wird). Da Interrupt-Handler nicht schlafen können, können sie keine Mutexe, Warteschlangen usw. verwenden. Dadurch bleiben so ziemlich Spinlocks übrig. Wenn ein Thread den Zugriff mit einem Interrupt-Handler synchronisieren muss, muss er auch denselben Spinlock verwenden.

Spinlocks sind nicht unbedingt eine Verschwendung. Sie sind für den Fall ohne Konflikte / Wartezeiten optimiert und können sehr schnell übernommen und freigegeben werden. In diesem Fall sind sie schneller und erfordern weniger Overhead als andere Synchronisationsprimitive.

James W.
quelle
2

Andere haben geantwortet. Ich werde die Fälle zusammenfassen, in denen Sie Spinlock verwenden würden, und Regeln, um Spinlock zu verwenden.

1. Wann wird Spinlock verwendet?

Antwort: In den folgenden Situationen.

  1. Der Thread, der das Schloss hält, darf nicht schlafen.
  2. Der Thread, der auf eine Sperre wartet, schläft nicht, sondern dreht sich in einer engen Schleife.

Bei ordnungsgemäßer Verwendung kann Spinlock eine höhere Leistung als Semaphor liefern. Beispiel: Intrrrupt-Handler.

2. Nach welchen Regeln werden Spinlocks verwendet?

Ans:

Regel - 1: Jeder Code, der den Spinlock enthält, kann den Prozessor aus keinem Grund freigeben, außer um Interrupts zu bedienen (manchmal auch dann nicht). Code, der Spinlock enthält, kann also nicht schlafen.

Grund: Angenommen, Ihr Fahrer mit Spinlock geht in den Schlaf. Beispiel: Ruft die Funktion auf copy_from_user()oder copy_to_user()oder die Kernel-Preemption startet, sodass ein Prozess mit höherer Priorität Ihren Code beiseite schiebt. Effektiv gibt der Prozess die CPU frei, die den Spinlock hält.

Jetzt wissen wir nicht, wann der Code die Sperre aufheben wird. Wenn ein anderer Thread versucht, dieselbe Sperre zu erhalten, dreht er sich sehr lange. Im schlimmsten Fall würde dies zu einem Deedlock führen.

Der Kernel-Preemption-Fall wird vom Spinlock-Code selbst behandelt. Immer wenn der Kernel-Code einen Spinlock enthält, ist die Vorauszahlung auf dem entsprechenden Prozessor deaktiviert. Selbst ein Einprozessorsystem muss die Vorauszahlung auf diese Weise deaktivieren.

Regel - 2: Deaktivieren Sie Interrupts auf der lokalen CPU, während der Spinlock gehalten wird.

Grund: Unterstützen Sie Ihren Treiber dabei, einen Spinlock zu verwenden, der den Zugriff auf das Gerät steuert, und geben dann einen Interrupt aus. Dadurch wird der Interrupt-Handler ausgeführt. Jetzt benötigt der Interrupt-Handler auch die Sperre, um auf das Gerät zugreifen zu können. Wenn der Interrupt-Handler auf demselben Prozessor ausgeführt wird, beginnt er sich zu drehen. Der Treibercode kann auch nicht ausgeführt werden, um die Sperre aufzuheben. SO wird der Prozessor für immer drehen.

Regel 3: Spinlocks müssen so kurz wie möglich gehalten werden.

Grund: Lange Sperrzeiten verhindern auch, dass der aktuelle Prozessor geplant wird. Dies bedeutet, dass ein Prozess mit höherer Priorität möglicherweise warten muss, um die CPU zu erhalten.

Dies wirkt sich also auf die Kernel-Latenz aus (Zeit, die ein Prozess möglicherweise warten muss, um geplant zu werden). Normalerweise sollten Spinlocks für die Zeitdauer gehalten werden, weniger als die CPU benötigt, um einen Contex-Wechsel zwischen Threads durchzuführen.

Regel -4: Wenn Sie Semaphoren und Spinlocks haben, müssen Sie beide nehmen. Nehmen Sie dann zuerst das Semaphor und dann den Spinlock.

Santosh
quelle
-3

Spinlocks und Mutexe werden aufgrund fehlender Ressourcen auf der CPU verwendet. Sie werden zu einem redundanten Erbe des 8-Bit-Register-basierten Von-Neumann-Designs. Dies ist die schlechteste Architektur, die heutzutage völlig unlogisch ist.

Leider sind die Funktionen des C / C ++ - Compilers in Bezug auf Funktionen, die mit den bis heute noch verfügbaren archaischen On-Chip-Ressourcen nicht in der Hardware eingeschlossen werden können, überproportional zur Hardware geworden. Caches sind daher in einem Uniprozessor einfach nicht über eine zweite Ebene hinaus wiedereintrittsfähig Der zeitaufwändige Kontext spart und viele neu eintretende SMPs werden fortgesetzt. Die Zukunft liegt bei FPGA-Geräten mit optimierten Build-Tools. Xilinix verfügt über einen neuen 14-nm-Prozess mit 3000 Verbindungen zwischen den A9-Quad-Cores und den programmierbaren Gate-Arrays, die halten Bis zu Hunderte von Megabits SRAM in Tabellen für fortschrittliches Zustandsmaschinendesign, das eine komplexe Float-Arithmetik / mehrdimensionale Vektor- / Eigentabellenreduzierung ermöglicht. So viel mehr als Ihr alter rollstuhlgebundener Compiler.

Mein Hardware-Design vor 25 Jahren hat erweiterte Hardware in eine DSP AD 21020 / CPU i960-Schnittstelle integriert. Es wurde klar, dass erweitertes Design viele Software-Probleme in diesem stromintensiven 160-Düsen-Drucker mit einer Breite von 1 Meter und 160 gelöst hat.

Personen, die mit der Kernel-Entwicklung vertraut sind, wurden eingeladen, ein kleines Team zu bilden, um eine neue Architektur zu evaluieren / zu modifizieren, die das Potenzial hat, Spinlocks / Cache-Misses / wiedereintretende SMP-Bedingungen zu ersetzen.

Rus Talis
quelle