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:
- Methodenaufrufe bzw. Methodenprologe
- Rückwärtssprünge in Schleifen
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: Threads als leichtgewichtige Prozesse
Up: Threads
Previous: Threads
  Inhalt
2001-02-28