Wie unterscheiden sich User-Level-Threads (ULTs) und Kernel-Level-Threads (KLTs) in Bezug auf die gleichzeitige Ausführung?

7

Folgendes verstehe ich; Bitte korrigieren / ergänzen:

In reinen ULTs führt der Multithread-Prozess selbst die Thread-Planung durch. Der Kernel merkt den Unterschied also nicht und betrachtet ihn als Single-Thread-Prozess. Wenn ein Thread einen blockierenden Systemaufruf tätigt, wird der gesamte Prozess blockiert. Selbst bei einem Multicore-Prozessor würde immer nur ein Thread des Prozesses ausgeführt, es sei denn, der Prozess ist blockiert. Ich bin mir nicht sicher, wie ULTs viel helfen.

In reinen KLTs plant der Kernel selbst dann, wenn ein Thread blockiert ist, einen anderen (Ready-) Thread desselben Prozesses. (Im Fall von reinen KLTs gehe ich davon aus, dass der Kernel alle Threads des Prozesses erstellt.)

Wie werden ULTs mithilfe von ULTs und KLTs in KLTs abgebildet?

    
AbhinavChoudhury 09.02.2013, 21:28
quelle

2 Antworten

17

Ihre Analyse ist korrekt. Der OS-Kernel kennt keine Threads auf Benutzerebene. Aus seiner Perspektive ist ein Prozess eine undurchsichtige Blackbox, die gelegentlich Systemaufrufe durchführt. Wenn dieses Programm über 100.000 Threads auf Benutzerebene, aber nur einen Kernel-Thread verfügt, kann der Prozess nur einen Threads auf Benutzerebene gleichzeitig ausführen, da nur ein Thread auf Kernel-Ebene zugeordnet ist. Auf der anderen Seite, wenn ein Prozess mehrere Kernel-Level-Threads hat, kann er mehrere Befehle parallel ausführen, wenn es einen Multicore-Rechner gibt.

Ein üblicher Kompromiss zwischen diesen besteht darin, dass ein Programm eine bestimmte Anzahl von Threads auf Kernel-Ebene anfordert und dann einen eigenen Thread-Scheduler verwendet, um die Threads auf Benutzerebene auf diese Kernel-Threads aufzuteilen. Auf diese Weise können mehrere ULTs parallel ausgeführt werden, und das Programm kann eine fein abgestufte Kontrolle darüber haben, wie Threads ausgeführt werden.

Wie funktioniert diese Zuordnung? Es gibt eine Reihe verschiedener Schemata. Sie können sich vorstellen, dass das Anwenderprogramm eines von mehreren verschiedenen Scheduling-Systemen verwendet. In der Tat, wenn Sie diese Substitution machen:

  

Kernel-Thread & lt; --- & gt; Prozessorkern

     

Benutzerthread & lt; --- & gt; Kernel-Thread

Dann könnte ein beliebiges Schema, mit dem das Betriebssystem Kernel-Threads auf Kerne abbilden könnte, auch dazu verwendet werden, Threads auf Benutzerebene auf Kernel-Threads zuzuordnen.

Hoffe, das hilft!

    
templatetypedef 09.02.2013 21:52
quelle
2

Vor allem anderen Vorlagentypdef ist die Antwort schön; Ich wollte einfach seine Antwort ein wenig erweitern.

Es gibt einen Bereich, den ich ein wenig erweitern wollte: Kombinationen von ULT's und KLTs . Um die Bedeutung zu verstehen (was Wikipedia für hybrid threading ), bedenken Sie die folgende Beispiele:

Betrachten Sie ein Multithread-Programm (mehrere KLTs), in dem es mehr KLTs als verfügbare logische Kerne gibt. Um effizient jeden Kern zu verwenden, wie Sie bereits erwähnt haben, soll der Scheduler KLTs, die blockieren, mit solchen sperren, die sich in einem Bereitschaftszustand befinden und nicht blockieren. Dies stellt sicher, dass der Kern seine Leerlaufzeit reduziert. Leider ist das Umschalten von KLTs für den Scheduler teuer und verbraucht relativ viel CPU-Zeit.

Dies ist ein Bereich, in dem Hybrid Threading hilfreich sein kann. Betrachten Sie ein Multithread-Programm mit mehreren KLTs und ULTs. Genau wie templatetypedef bemerkt, kann für jede KLT nur eine ULT gleichzeitig ausgeführt werden. Wenn ein ULT blockiert, wollen wir ihn immer noch für einen ausschalten, der nicht blockiert. Glücklicherweise sind ULTs viel leichter als KLTs in dem Sinne, dass einem ULT weniger Ressourcen zugewiesen werden und sie keine Interaktion mit dem Kernel-Scheduler benötigen. Im Wesentlichen ist es fast immer schneller, ULTs auszuschalten, als KLTs auszuschalten. Dadurch können wir die Leerlaufzeit eines Kerns im Vergleich zum ersten Beispiel erheblich reduzieren.

Das hängt natürlich von der Threading-Bibliothek ab, die für die Implementierung von ULTs verwendet wird. Es gibt zwei Möglichkeiten (die ich mir vorstellen kann), um ULTs zu KLTs zu "mappen".

  1. Eine Sammlung von ULT für alle KLTs

    Diese Situation ist ideal für ein System mit gemeinsam genutztem Speicher. Es gibt im Wesentlichen einen "Pool" von ULTs, auf den jede KLT Zugriff hat. Idealerweise würde der Threading-Bibliothek-Scheduler ULTs auf Anfrage jeder KLT zuweisen, im Gegensatz zu den KLTs, die einzeln auf den Pool zugreifen. Letzteres könnte zu Racebedingungen oder Deadlocks führen, wenn sie nicht mit Schlössern oder Ähnlichem implementiert werden.

  2. Eine Sammlung von ULTs für jeden KLT ( Qthreads )

    Diese Situation ist ideal für ein verteiltes Speichersystem. Jede KLT hätte eine ULT-Sammlung zu führen. Der Nachteil ist, dass der Benutzer (oder die Threading-Bibliothek) die ULTs zwischen den KLTs aufteilen muss. Dies kann zu einem Lastungleichgewicht führen, da nicht garantiert ist, dass alle ULTs die gleiche Menge an Arbeit haben, um ungefähr die gleiche Zeit zu vervollständigen und zu vervollständigen. Die Lösung dafür ist ULT Migration zu ermöglichen; das heißt, ULTs zwischen KLTs zu migrieren.

Alex Brooks 26.07.2013 21:36
quelle