next up previous contents
Next: Threads als leichtgewichtige Prozesse Up: Threads Previous: Threads   Inhalt


Threads auf Anwendungsebene

Werden Threads in der VM allein auf Anwendungsebene realisiert, ohne dabei auf Funktionalität des Betriebssystems zurückzugreifen, so spricht man von Implementierungen im user space. Erzeugung, Zuteilung von Rechenzeit und Synchronisation der Threads finden statt, ohne daß entsprechende Betriebssystemfunktionen verwendet werden. Für das Betriebssystem stellt sich die VM als ein nicht nebenläufiger Prozeß dar. Implementierungen im user space werden auch als ,,n:1-Implementierungen`` bezeichnet, da hier alle Programmiersprachen-Threads auf einen Betriebssystem-Thread abgebildet werden.

Dies kann aus verschiedenen Gründen geschehen:

Verfügbarkeit
Eine nebenläufige Programmiersprache soll auf einem System implementiert werden, das die Ausführung mehrerer Threads nicht unterstützt. So existieren Java-Implementierungen für PalmOS und Windows 3.1, obwohl keine dieser beide Plattformen über ein Thread-Konzept verfügt.
Effizienz
Kontextwechsel zwischen zwei Threads erfordern keinen Aufruf des Betriebssystem-Schedulers. Dieser Übergang vom user space in den kernel space ist aufwendig und belastet die Effizienz des Systems erheblich. [Anderson et al., 1991] nennen ein bis zwei Größenordnungen Zeitdifferenz zwischen Kontextwechseln auf Anwendungsebene und auf Systemkernebene.
Flexibilität
Durch eine eigene Implementierung kann die VM Thread-Funktionalitäten realisieren, die vom Betriebssystem nicht zur Verfügung gestellt werden. Beispielsweise spezifiziert der Smalltalk Sprachstandard präzise einen prioritätsbasierten Scheduler, der von der VM entsprechend umgesetzt werden muß.
Portabilität
Je weniger Betriebssystemschnittstellen in einer Implementierung genutzt werden, desto einfacher kann diese auf ein anderes System übertragen werden. Insbesondere die Standardisierung von Thread-Schnittstellen ist erst vor kurzem entscheidend vorangeschritten -- Implementierungen des POSIX Standards 1003.1c-1996 (,,POSIX Threads``) [POSIX, 1996] sind erst seit ca. 1998 ausreichend auf UNIX-Systemen verfügbar. Die Java-Referenzimplementierung Classic VM[Sun Microsystems, 2000a], die Sun seinen Lizenznehmern zur Verfügung stellt, enthält daher eine Thread-Implementierung im user space (,,green threads``).
Einfache Implementierung
In einer Thread-Implementierung im user space wird der Scheduler nur explizit aufgerufen oder läßt sich in der Regel ausschalten. Teile der Maschinenimplementierung brauchen daher nicht thread-sicher implementiert zu werden -- ein nicht zu unterschätzender Vorteil.

Implementierungen um user space lassen sich weiter nach ihrem Unterbrechungsmechanismus klassifizieren (preemption):

Freiwillige Prozessoraufgabe
(voluntary yield). Der Thread behält solange die Kontrolle, bis der Anwendungscode einen expliziten Aufruf an den Scheduler tätigt. Dieser kann dann den Thread-Zustand sichern und einen Thread-Wechsel vornehmen. Diese Technik erfordert natürlich entsprechend strukturierte Anwendungsprogramme. Für eine virtuelle Maschine ist dies jedoch unproblematisch, denn der ,,Anwendungscode`` ist in diesem Fall der Interpreter oder der vom Compiler generierte Code und kann damit automatisch entsprechend instrumentiert werden. Nur beim Aufruf externen Codes besteht die Gefahr, daß ein Thread über Gebühr lange den Prozessor belegt oder gar durch Warten auf ein externes Ereignis die Gesamtheit der Threads blockiert. Steht eine Systemthread-Schnittstelle zur Verfügung, so können für diese Fälle neue Betriebssytem-Threads oder LWP gestartet werden. Dieser Ansatz führt hin zu Two-Level-Implementierungen, die wir in 5.2.3 beschreiben. Es reicht aus, zwei Operationen zu möglichen Unterbrechungspunkten zu machen:

Codeblöcke zwischen zwei solchen Punkten werden linear durchlaufen und sind daher im Allgemeinen ausreichend kurz, um häufige Thread-Wechsel zu ermöglichen.
Zeitgesteuerte Unterbrechung
Durch einen Betriebssystemmechanismus (z.B. UNIX Signale) können regelmäßig Unterbrechungen des Benutzerprogramms verursacht und die Kontrolle an den Scheduler übergeben werden. Dieser Mechanismus funktionert im Gegensatz zur freiwilligen Prozessoraufgabe in der Regel auch dann, wenn gerade Code einer externen Bibliothek ausgeführt wird.

Die wichtigesten Vorteile von Thread-Implementierungen auf Anwendungsebene sind schnelle Kontextwechsel und ihre Portabilität. Da sie mit relativ geringen Kosten realisiert werden können, eignen sie sich hervorragend für Systeme mit einer hohen Zahl von Threads. Gewichtige Nachteile stellen die fehlende Nutzung mehrer Prozessoren sowie der aufwendige Umgang mit blockierenden Systemaufrufen dar.


next up previous contents
Next: Threads als leichtgewichtige Prozesse Up: Threads Previous: Threads   Inhalt

2001-02-28