<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<document>
   <head>
      <pagetitle>Scriptum zur Vorlesung Systemarchitekturen</pagetitle>
      <metatags description="Scriptum zur Vorlesung Systemarchitekturen" keywords="Rechnerarchitektur, Betriebssysteme, Verteilung" url="http://www.jeckle.de/vorlesung/sysarch/script.html">
         <nocache/>
         <robots revisit-after="10 days"/>
         <css/>
      </metatags>
   </head>
   <body>
      <navigation titleimage="sysarch.png">
         <navup reference="Vorlesung Systemarchitekturen" destinationuri="index.html"/>
      </navigation>
      <region numbered="yes">
         <topic name="motEinf">Motivation und Einführung</topic>
         <p xml:base="file:/I:/development/vorlesung/sysarch/abstract.xml">Streitfragen um die <gerquot>richtige</gerquot> Architektur von Betriebssystemen und Rechnern bestimmen vielfach die (ver-)öffentlichte Meinungsbildung und die Werbeaussagen großer Hersteller.<br/>
    Jenseits der plakativen und vermeindlichen Vergleiche und Entwicklungssprünge haben sich jedoch die der Rechnerarchitektur und dem Aufbau von Betriebssystem zugrundeliegenden Konzepte in den letzten Jahren nicht umwälzend geändert. Vielmehr existiert eine stabile Basis gut verstandener und in der Praxis erprobter Grundlagen, die auch in modernen Rechnerarchitekturen und Betriebssystemen Anwendung finden. Hierzu zählt der Bestand an Wissen über Aufbau und interne Organisation von Prozessoren und Betriebssystemen, hierbei insbesondere Aspekte der Ablaufsteuerung, Speicherverwaltung und des Zugriffs auf Hintergrundspeicher. Gleichzeitig eroberten sich verteilte Systeme in der jüngeren Vergangenheit einen solch zentralen Stellenwert in der Anwendung, daß Kenntnisse über deren Basismechanismen inzwischen auch als Grundlagenwissen anzusehen sind.</p>
         <subtopic name="history">Rechner- und Betriebssystementwicklung</subtopic>
         <p>Betriebssysteme und die Architektur der sie ausführenden Hardware sind einem stetigen Wandel unterworfen und haben sich im Verlauf der Entwicklung elektronischer Datenverarbeitung stark verändert. Im Kern bilden beide zusammen Triebfeder und Schrittmacher der verschiedenen Generationen und wirkten mit ihren Konzepten vielfach stilbildend für die jeweils aktuelle Form der Datenverarbeitung.</p>
         <p>Technisch gesehen ist ein Betriebssystem lediglich ein Programm, welches durch die zugrundeliegende Hardware zur Ausführung gebracht wird. Jedoch nimmt dieser Programmtyp eine solche zentrale Stellung ein, daß vielfach Hardware und Betriebssystem (immernoch) als Einheit betrachtet werden, obwohl sich inzwischen beide voneinander entkoppelt -- jedoch durch starke Wechselwirkungen geprägt -- entwickeln.</p>
         <p>Aufgrund dieser zentralen Stellung definiert DIN 44300 den Begriff <em>Betriebssystem</em> daher als: <gerquot>Die Programme eines digitalen Rechensystems, die zusammen mit den Eigenschaften dieser Rechenanlage die Basis der möglichen Betriebsarten des digitalen Rechensystems bilden und die insbesondere die Abwicklung von Programmen steuern und überwachen</gerquot>.</p>
         <p>Nachfolgend wird ein kurzer Überblick von Hardware-, Rechner- und Betriebssystemgenerationen gegeben, welche die historische Entwicklung kurz umreißt und einen Einblick in die Fortschritte der zugrundeliegenden Konzepte bietet. Gleichzeitig finden typische Interaktionsformen mit der aus Hardware und Betriebssystem gebildeten Recheneinheit Berücksichtigung.</p>
         <SimpleTable>
            <tr>
               <td>Zeitraum</td>
               <td>Schaltungsrealisierung</td>
               <td>Verbreitung</td>
               <td>Typische Betriebssysteme</td>
               <td>Typische Programmiersprachen</td>
               <td>Geschwindigkeit</td>
               <td>Beispiele</td>
            </tr>
            <tr>
               <td>1945-1955</td>
               <td>Relais, später Röhren</td>
               <td>wenige Exemplare (Univac: 46 Stück)</td>
               <td>
                  <em>Keine</em>
               </td>
               <td>Steckkarten, später Maschinencode</td>
               <td>10<sup>3</sup>Ops./Sec.</td>
               <td>Univac</td>
            </tr>
            <tr>
               <td>1955-1965</td>
               <td>Transistoren und Dioden</td>
               <td>Hunderte</td>
               <td>Hardwarespezifisch (z.B. Multics, )</td>
               <td>Assembler, später FORTRAN, Algol60 und COBOL</td>
               <td>10<sup>4</sup>Ops./Sec.</td>
               <td>IBM <a href="http://www-1.ibm.com/ibm/history/exhibits/mainframe/mainframe_PP1401.html">1401</a>, <a name="IBM7094" href="http://www-1.ibm.com/ibm/history/exhibits/mainframe/mainframe_PP7094.html">7094</a>, DEC PDP</td>
            </tr>
            <tr>
               <td>1965-1980</td>
               <td>Integrierte Schaltungen</td>
               <td>Tausende</td>
               <td>Hardwarespezifisch (z.B. OS/360, ...)</td>
               <td>höhere Programmierspachen, erste Programmiermethoden</td>
               <td>10<sup>6</sup>Ops./Sec.</td>
               <td>
                  <a href="http://www.cedmagic.com/history/ibm-system-360.html">IBM 360</a>
               </td>
            </tr>
            <tr>
               <td>ab 1980</td>
               <td>Hoch integrierte Schaltungen (VLSI)</td>
               <td>Millionen</td>
               <td>Prozessorspezifisch (z.B. MS-DOS, Windows, Minix, Linux)</td>
               <td>Höhere Programmiersprachen (C++, Java, ...)</td>
               <td>min. 10<sup>7</sup>Ops./Sec.</td>
               <td>Intel Prozessoren, AMD, Motorola ...</td>
            </tr>
         </SimpleTable>
         <p>Handelte es sich bei der          <name>Univac</name> noch um ein eher experimentelles und nur in wenigen Stückzahlen gefertiges Gerät, die sich durch hohe Anschaffungs- und Betriebskosten sowie immensen Platzbedarf und geringe Zuverlässigkeit auszeicheten, so beanspruchen die die ab 1955 entwickelten Maschinen ihre Rolle als erste kommerziell erfolgreiche Systeme. Für sie hat sich die Gattungsbezeichnung <a href="http://de.wikipedia.org/wiki/Mainframe">
               <em>
                  <keyword>Mainframe</keyword>
               </em>
            </a> eingebürgert. Die Arbeit mit den Rechnern dieser Generation läuft ausschließlich offline im <em>
               <keyword>Stapelverarbeitungsbetrieb</keyword>
            </em> (auch: <em>
               <keyword>batch-Betrieb</keyword>
            </em>),  d.h. die zu berechnenden Aufgaben (<em>
               <keyword>jobs</keyword>
            </em>) werden nicht interaktiv abgearbeitet, sondern nach ihrer Zeitdauer manuell durch einen menschlichen Operator zusammengestellt und der Maschine durch Lochkarten vorgelegt. Zumeist sind die Maschinen für genau ein konkretes Anwendungsgebiet (z.B. numerische Berechnungen) konzipiert.<br/>Später entwickelt sich daraus die <em>
               <keyword>Stapelverarbeitung</keyword>
            </em>,  welche die Eingaben in Form von Magnetbändern -- jedoch immernoch seriell und nicht interaktiv -- akzeptiert.<br/>Ab 1965 ist der Versuch einer Konsolidierung der verschiedenen Hardwarestränge seitens der Hersteller zu spüren. So fertigt IBM mit dem System 360 ein Serie kompatibler Rechner (d.h. die auf einer Systemvariante ablauffähige Software kann auch auf einem anderen Mitglied der Rechnerfamilie zur Ausführung gebracht werden). In dieser Entwicklungsgeneration steht bereits sowiel Rechenkapazität zur Verfügung, daß ein aktuell bearbeiteter Auftrag die Maschinen nicht mehr vollständig auszulasten vermag. Daher wird mit dem Konzept des <em>
               <keyword>Multiprogramming</keyword>
            </em> die Möglichkeit zur Bearbeitung einer anderen anstehenden Aufgabe geschaffen, während sich die aktuell in Bearbeitung befindliche im Wartezustand (etwa auf Ende einer Ein-/Ausgabeoperation) befindet. Diese Ausführungsform bedingt jedoch eine zusätzliche Komplexität im Aufbau der Verwaltungsfunktionen, da diese nun die gleichzeitige Präsenz verschiedener Programme im verwalteten Speicher zu berücksichtigen haben. Darüberhinaus ist der Programmablauf so zu organisieren, daß sich die verschiedenen Programme geschützt voneinander abgearbeitet werden und sich nicht gegenseitig beinträchtigen.<br/>In Erweiterung des Multiprogrammbetriebes wurde mit <em>
               <keyword>Timesharing</keyword>
            </em> eine Variante dieser Betriebsform eingeführt, die es erstmals mehreren Benutzern gestattete gleichzeitig online am System zu Arbeiten. Durch schnelles Umschalten zwischen den Aufgaben der Einzelnutzer entsteht so die Illusion der alleinigen Arbeit am System.<br/>Mit wachsenden Hauptspeichergrößen führt die dritte Entwicklungsgeneration (die sog. <em>
               <keyword>Minicomputer</keyword>
            </em>) auch Techniken zur Lösung der Abhängigkeit von langsamen Speichertypen ein. So wurde mit <em>Simultaneous Peripheral Operation On Line</em> -- kurz <em>
               <keyword>Spooling</keyword>
            </em> -- ein Verfahren eingeführt alle übergebenen Aufgaben zunächst von Lochkarten einzulesen und auf Platten zwischenzuspeichern.<br/>Aus einer Weiterentwicklung des Timesharing-Systems <em>
               <keyword>MULTIC</keyword>
            </em> (MULTIplexed Information and Computing System) entwickelt sich ab den frühen 1970er Jahren das System <em>
               <keyword>UNIX</keyword>
            </em>,  welches zunächst auf der PDP-7-Hardware entwickelt, jedoch später auch für andere Plattformen portiert, wurde.</p>
         <p>Die Hardware- und Betriebssystementwicklung ab 1980 ist begleitet durch einen massiven Siegeszug an einem immer größer werdenen Massenmarkt. Die Fortschritte der Fertigungstechnik erlauben eine immer weiter voranschreitende Packungsdichte der integrierten Schaltungen und verbilligen gleichzeitig deren Herstellung. Die so gefertigten Hardwaren (als <em>
               <keyword>Personal Computer</keyword>
            </em> (<em>
               <keyword>PC</keyword>
            </em>) oder auch <em>
               <keyword>Mikrocomputer</keyword>
            </em> bezeichnet) entsprechen in ihren Strukturprinzipien weitestgehend den Minicomputern der Vorgängergeneration, jedoch zu einem sehr viel niedrigeren Verkaufspreis.</p>
         <p>Als eines der ersten Betriebssysteme für dies neuen Rechnergeneration stand <em>
               <keyword>CP/M</keyword>
            </em> (<em>Control Program for Microcomputers</em>) zur Verfügung, welches den 1974 durch <a href="http://www.intel.com">Intel</a> vorgestellten 8-Bit Mikroprozessor <a href="http://www.dotpoint.com/xnumber/intel_8080.htm">8080</a> unterstützte.<br/>Seit den frühen 1980er Jahren finden Prozessoren dieses Typs Verwendung in der, zunächst ausschließlich durch <a href="http://www.ibm.com">IBM</a> vorangetriebenen, PC-Line. Nachdem Verhandlungen zwischen den Autoren des <a href="http://www.seasip.demon.co.uk/Cpm/">CP/M-Systems</a> und IBM über die Nutzung des Betriebssystems für den <a href="http://inventors.about.com/library/weekly/aa031599.htm">IBM PC</a> scheiterten lieferte <a href="http://www.microsoft.com">Microsoft</a> mit <em>
               <keyword>MS-DOS</keyword>
            </em> (<em>
               <a href="http://inventors.about.com/library/weekly/aa033099.htm">Microsoft Disk Operating System</a>
            </em>) das erste kommerziell vertriebene Betriebssystem für diesen Rechnertyp.</p>
         <p>Gegen Ende der 1980er Jahre geriet die Benutzbarkeit der -- damals schon in hohen Stückzahlen verkauften PCs -- immer stärker ins Zentrum des Interesses. Als Vorreiter führte der Hersteller Apple auf seiner nicht IBM-kompatiblen Hardware eine <a href="http://www.pegasus3d.com/apple_screens.html">graphische Oberfläche</a> (<em>
               <keyword>GUI</keyword>
            </em> -- <em>Graphical User Interface</em>) zur Bedienung des Rechners ein. Deren, ursprünglich am <a href="http://www.parc.xerox.com/">Xerox PARC-Forschungszentrum</a> entwickeltes Konzept, gewann in der Folge immer größere Bedeutng und wurde letztlich durch das MS-DOS-Programm <em>
               <keyword>Windows</keyword>
            </em> popularisiert.</p>
         <p>Seit 1995 vertreibt Microsoft ein -- ebenfalls <em>Windows</em> genannte -- Familie eigenständiger PC-Betriebssysteme, die den kommerziellen Massenmarkt beherrscht.<br/>Gleichzeitig findet vielfach -- insbesondere auf Netzwerkrechnern (Servern) -- die ursprünglich durch den finnischen Studenten          <name>
               <a href="http://www.cs.helsinki.fi/u/torvalds/">Linus Torvalds</a>
            </name> entwickelte -- Unix-Variante <em>
               <keyword>Linux</keyword>
            </em> breiten Einsatz.</p>
         <p>Hinzu tritt in den 1990er Jahren der Trend zur verteilten Verarbeitung auf Basis durch Netzwerke gekoppelter Rechner.</p>
         <subtopic name="per">Peripherie</subtopic>
         <p>Parallel zur Entwicklung der Kernhardware und der darauf ablaufenden Betriebssysteme entwickelt sich die Landschaft der mit der Berechnugnseinheit kommunizierenden Peripheriegeräte. Hierbei ist der Begriff des Peripheriegerätes jedoch aus Sicht des Zentralprozessors interpretiert und daher entsprechend weiter gefaßt als seine landläufige Definition, welche ausschließlich an der Zentraleinheit (bestehend aus CPU, Speicher und Bussen) anschließbare Geräte berücksichtigt.</p>
         <p>Die erste Rechnergeneration verfügte noch über keine dedizierten Peripheriegeräte. Eingaben wurden direkt, durch Schalttafeln und Erstellung von Hardwareverbindungen, an der Maschine vorgenommen; Ausgaben ebendort -- von Lampen oder anderen Signalgebern -- abgelesen.</p>
         <p>Ab den 1955er Jahren finden sich zunehmen externe Geräte zur Abwicklung und dauerhaften Speicherung der verarbeiteten Daten. Urvater des Ein- und Ausgabegerätes waren zunächst Lochstreifen, welche zur Steuerung automatisierter Webstühle bereits im 19 Jahrhundert und später zur Darstellung von Morsezeichen Verwendung fanden, die später durch Lochkarten abgelöst wurden.<br/>Die Lochkarte bot, neben der vergleichsweise einfachen manuellen Handhabung die Möglichkeit bestehende -- zuvor durch Tabelliermaschinen verarbeitete -- Datenbestände weiter einsetzen zu können.<br/>Im Deutschen war damals der Begriff <em>
               <a href="http://www-1.ibm.com/ibm/history/exhibits/attic/attic_071.html">
                  <keyword>Hollerithmaschine</keyword>
               </a>
            </em> -- nach          <name>
               <a href="http://de.wikipedia.org/wiki/Herman_Hollerith">H. Hollerith</a>
            </name> , der bereits zur Abwicklung der US-Volkszählung von 1890 Lochkarten einsetzte -- für lochkartenbetriebene Rechner gängig.<br/>Zur Senkung der Fehlerrate (etwa durch Vertauschung zweier Lochkarten) und Erhöhung der Verarbeitungsgeschwindigkeit wurden die Lochkarten zunehmend durch Magnetbänder ersetzt.<br/>Das Aufkommen von <em>
               <keyword>Ferritkernspeicher</keyword>
            </em> n  markiert den Übergang zu Speicherorganisationsformen mit wahlfreiem Zugriff, da jeder einzelne Speicherring (Bit) separat angesprochen werden konnte.</p>
         <p>Die Grundidee der Ferritkernspeicher (auch als <em>
               <keyword>Ringkernspeicher</keyword>
            </em> bekannt) hat sich <a href="http://www.heise.de/tp/deutsch/inhalt/lis/13014/1.html">bis heute</a> erhalten, wenngleich ihre technische Realisierung im Lauf der Zeit natürlich mit den modernisierten Fertigungsmethoden Schritt hielt.<br/>In einem Ringkernspeicher sind parallel zum Rahmen dünne Metalldrähte -- die Steuerdrähte -- gespannt, die mit Strom beschickt werden können. Zusätzlich verläuft ein Diagonaldraht (Lesedraht), der alle alle magnetisierbaren Ringkerne verbindet.</p>
         <p>Jeder Ring kann separat durch gerichteten Stromfluß in den Steuerdrähten auf zwei verschiedene Weisen magnetisiert werden. Fliest der horizontale Steuerstrom transversal (in der Abbildung in <em>P</em> -Richtung) und der vertikale nach unten (ebenfalls <em>P</em>), so entsteht eine Magnetisierung die diagonal nach unten gerichtet ist. Im umgekehrten Falle (Stromrichtungen: aufwärts und linksgerichteter Strom (jeweils durch <em>N</em>) entsteht ein entgegengesetztes, d.h. diagonal nach links-oben gerichtetes Magnetfeld.</p>
         <illustration id="ringkernspeicher" width="420" caption="Aufbau eines Ringkernspeichers" gfx="sysarch/rks.png"/>
         <p>
            <small>Quelle: J. A. Rajchmann: A Myriabit Magnetic Core Matrix Memory. IRE Proceedings 1408, Okt. 1953, IEEE 1953.</small>
         </p>
         <p>Zum Auslesen des Speicherzustandes wird die Hystereseeigenschaft ausgenutzt und testweise ein beliebiger Beschreibungsvorgang durchgeführt. Ändert sich durch diesen die zuvor präsente Magnetisierung, so wird im Lesedraht ein Stromstoß induziert, andernfalls nicht.</p>
         <p>Als Weiterentwicklung der Ringkernspeicher bürgerten sich <em>Trommelspeicher</em> ein, welche die Datenspeicherung auf einer magnetisierten rotierenden Trommel vornimmt. Das Auslesen geschieht durch am Gehäuse fest angebrachte Magnetköpfe.<br/>Seit den 1960er Jahren (erster<gerquot>Masseneinsatz</gerquot>in IBM 305) kommen zunehmend magnetische Speicherplatten mit wahlfreiem als externe Speicher in den Masseneinsatz. Ihre technischen Basiskonzepte unterscheiden sich kaum von aktuellen Festplatten.</p>
         <p>Mit dem Aufkommen des interaktiven Timesharing-Betriebes wurden auch neue Formen der Ein- und Ausgabeverarbeitung notwendig, da nicht mehr jeder Nutzer direkten Zugriff auf das physische Speichermedium haben konnte. Daher entstanden visuelle Endgeräte zur Präsentation der Daten, sowie Tastaturen zu ihrer Erfassung.</p>
         <p>Der Siegeszug der graphischen Benutzeroberflächen in den 1980er Jahren führte die <em>
               <keyword>Maus</keyword>
            </em> als neues Eingabemedium als festen Bestandteil der Rechnerperipherie ein.</p>
         <p>Aktuelle Trends schließen Sprachein- und Ausgabe, sowie tastaturbasierte Eingabeformen mit reduzierter Tastenzahl (etwa auf Mobiltelephonen und PDAs) ein.</p>
         <subtopic name="cpu">Zentralprozessoren</subtopic>
         <p>Wesentliches Element einer Rechnerarchitektur ist der <em>
               <keyword>Zentralprozessor</keyword>
            </em> (engl. <em>central processing unit</em>,   kurz:<keyword>CPU</keyword>), welcher die Hauptteile der Verarbeitung übernimmt. Die CPU, deren stetiger Leistungszuwachs sich in der Vergangenheit nach dem <em>
               <a href="http://de.wikipedia.org/wiki/Mooresches_Gesetz">
                  <keyword>Moore'schen Gesetz</keyword>
               </a>
            </em> (es sagt auf Basis empirischer Daten eine Verdopplung der Transistorenanzahl pro Chip (und damit der Leistungsfähigkeit) alle 18 Monate voraus) entwickelte, ist in jüngerer Zeit selbst zum Marketingbestandteil avanciert.<br/>Gleichzeitig rücken die internen Realisierungsdetails stark in das Bewußtsein des Anwenders, da sie die Leistungsfähigkeit und wirtschaftlich einer gegebenen Hardware stark beeinflußen.</p>
         <p>Historisch gesehen determiniert die verwendete CPU typischerweise die auf einer Hardware ausführbaren Programme.    So sind übersetze Anwendungen im Normalfall nur auf einem bestimmten Prozessortyp ausführbar, außer die verfügbare Hardware oder eine darauf angebotene Softwarekomponente bieten eine simulierende Unterstützung der ursprünglichen Zielhardware an. Unter Verwendung dieser simulierenden Unterstützung verhält sich ein Programm, welches für einen anderen Prozessortyp übersetzt wurde unter Eingabe derselben Daten so als würde es auf der ursprünglichen Hardware ausgeführt werden. Es handelt sich mithin um eine programmgesteuerte Imitation des Orginalprozessors.<br/>Diese imitierende Simulation kann an Leistungsfähigkeit die ursprüngliche Zielhardware durchaus signifikant übertreffen. Aus diesem Grunde hat IBM für das System 360 den Begriff der <em>
               <keyword>Emulation</keyword>
            </em> (wohl auch um den negativen Beigeschmack der Begriffe <em>
               <a href="http://de.wikipedia.org/wiki/Simulation">Simulation</a>
            </em>  und  <em>Imitat</em>  zu vermeiden) geprägt, deren Prozessor Programme für den damals kommerziell erfolgreichen Großrechnertyps IBM 7070 ausführen konnte. (<a href="index.html#ceruzzi">[Cer03, S. 188]</a>)</p>
         <p>Aktuelle Prozessoren folgen dem in  <illustrationLink ref="cpu"/>  dargestellten schematischen Aufbau, welche die zentralen Architekturkomponenten <em>
               <keyword>Leitwerk</keyword>
            </em> (engl. <em>
               <keyword>control unit</keyword>
            </em> (CU)), <em>
               <keyword>Rechenwerk</keyword>
            </em> (engl. <em>
               <keyword>arithmetic and logic unit</keyword>
            </em> (<keyword>ALU</keyword>), Registersatz und typischerweise den Mikroprogrammspeicher umfaßt.</p>
         <illustration id="cpu" width="600" caption="Schematischer Aufbau eines Zentralprozessors" gfx="sysarch/cpu.png"/>
         <p>Diese, nach dem Initiator als          <name>von-Neumann</name> -Architektur, bezeichnete Organisationsweise prägt den Aufbau von Rechenanlagen seit den späten 1940er Jahren und ist im Kern bis heute gültig; wenngleich sich in der Gegenwart verschiedene Engpässe dieses Ansatzes zeigen.</p>
         <p>Die Kerngedanken der<keyword>von-Neumann-Architektur</keyword>sind:</p>
         <ul>
            <li>
               <b>Einteilung</b>der Verarbeitungseinheit in Leit- und Rechenwerk, Hauptspeicher, Ein- und Ausgabeeinheiten sowie Verbindungen (Busse) dazwischen.<br/>Dabei bilden Leit- und Rechenwerk die CPU.</li>
            <li>Die verarbeiteten Daten werden binär repräsentiert und taktgesteuert in Worten fester Bitlängen verarbeitet.</li>
            <li>Programme und Daten werden in einem gemeinsamen Hauptspeicher unsepariert und gekennzeichnet abgelegt. Der Hauptspeicher ist fortlaufend organisiert und wird durch eineindeutige Adressen angesprochen.</li>
            <li>Die Verarbeitung von Programmen und Daten erfolgt sequentiell typischerweise in der Reihenfolge der abgespeicherten Programmbefehle. Verzweigungen, Schleifen und Sprungbefehle können Abweichungen von der sequentiellen Abarbeitungsreihenfolge bedingen.</li>
         </ul>
         <p>Die Festlegungen der von-Neumann-Architektur haben sich zunehmend als Gründe verschiedener Leistungsengpässe erweisen, die durch partielle Aufweichungen dieser Architekturprinzipien behoben werden können.</p>
         <p>Einige bekannte Engpässe der von-Neumann-Architektur:</p>
         <ul>
            <li>Gleichbehandlung von Daten und darauf operierenden Programmen.<br/>Die Zugriffe auf die im Hauptspeicher identisch abgelegten Daten und Programme können sich gegenseitig behindern, da keine separaten Ein-/Ausgabekanäle für diese verarbeiten Inhalte vorgesehen sind.<br/>Zusätzlich eröffnet die nicht erfolgte Separierung von Daten und Programmen eine besondere Klasse von Bedrohungsszenarien. So können geeignet gestaltete Datenblöcke sog. Pufferüberläufe (engl. <em>
                  <keyword>buffer overflow</keyword>s</em>) provozieren, bei denen über Datenbereiche ausführbarer (Angriffs-)Code in den Programmbereich eingeschleußt wird.<br/>Beiden Problemen kann durch Einführung getrennter Speicher und Busse für Daten und Programme (insbesondere im Umfeld schneller Zwischenspeicher sog. <em>Caches</em>) begegnet werden (Havard-Architektur). Ein neuerer Ansatz zur Beibehaltung der Ablage im selben Speicherbereich wird durch Einführung einer expliziten Kennzeichung nicht ausführbarer Datenbereiche im Hauptspeicher realisiert.</li>
            <li>Sequentielle Verarbeitung.<br/>Die Leistungsfähigkeit einer Hardware läßt sich durch Schaffung von Möglichkeiten zur gleichzeitigen (parallelen) Verarbeitung einzelner Befehle steigern. Ansätze hierzu bilden:<ul>
                  <li>
                     <a href="#ILP">Instruction Level Parallelism</a>
                  </li>
                  <li>Multithreading</li>
                  <li>Multiprozessorsysteme</li>
               </ul>
            </li>
            <li>Festgelegte Befehlsabfolge.<br/>Die Verarbeitungsreichenfolge der Einzelbefehle eines Programmes kann von der Reihenfolge ihres Auftretens im Programm abweichen. In Verbindung mit Parallelitätsansätzen lassen sich so zeitaufwendige Befehlsfolgen<gerquot>im Voraus</gerquot>berechnen und auf diesem Wege die Verarbeitungszeit senken.<br/>Voraussetzung hierfür ist der flexible Umgang mit den belegbaren Registern, d.h. im Idealfalle die Existenz mehrerer Registersätze.</li>
         </ul>
         <p>Die in <illustrationLink ref="cpu"/> zusammengestellten Kernkomponenten einer CPU erfüllen festgelegte Aufgaben. Ihre Arbeitsteilung bildete sich im Laufe der Entwicklungsgeschichte heraus und ist bis heute aktuellen Prozessorarchitekturen nahezu unverändert präsent.</p>
         <subsubtopic>Rechenwerk (ALU)</subsubtopic>
         <p>Das Rechenwerk führt die Rechenoperationen auf den speicherresidenten Operatoren durch.</p>
         <p>Aktuelle CPU-Architekturen (wie Intel Pentium, AMD Athlon und Power PC) verfügen innerhalb einer CPU über mehrere Rechenwerke, insbesondere solche für Fest- und Gleitkommaoperationen.</p>
         <p>Typischerweise bietet ein Rechenwerk die folgenden grundlegenen Operationstypen an:</p>
         <ul>
            <li>Arithmetische Operationen: Addition, Subtraktion, Multiplikation und Division.</li>
            <li>Logische Operationen: AND, OR, NOT, NOR, XOR, ...</li>
            <li>Bitmanipulationen: Rotation, Verschiebung und Vergleiche.</li>
         </ul>
         <p>Als Beispiel einer ALU-Komponente zur Addition n-stelliger Binärzahlen mit Übertrag sei der <em>
               <keyword>Ripple-Carry-Addierer</keyword>
            </em> betrachtet:</p>
         <p>Grundkomponente eines solchen Addierers sind eine Reihe verschalteter Volladdierer (engl. <em>full adder</em> (FA)), wie er schematisch in <illustrationLink ref="FA"/> abgebildet ist.</p>
         <illustration id="cpu" width="200" caption="Aufbau eines Volladdierers" gfx="sysarch/Volladdierer_Aufbau.png"/>
         <p>
            <small>Abbildung aus: <a href="http://de.wikipedia.org/wiki/Volladdierer">Wikipedia, Volladdierer</a>
            </small>
         </p>
         <p>Anmerkung: Bedeutung der Schaltsymbole</p>
         <illustration id="cpu" width="282" caption="Schaltsymbole" gfx="sysarch/schaltsym.png"/>
         <p>Im Unterschied zum <a href="http://de.wikipedia.org/wiki/Halbaddierer">
               <keyword>Halbaddierer</keyword>
            </a> liefert der Volladdierer nicht nur einen Übertrag im Rahmen der Ergebnisberechnung, sondern akzeptiert diesen auch als Eingabe (einer möglicherweise vorhergehenden Additionsoperation).</p>
         <p>Durch die Hintereinanderschaltung meherer Volladdierer und Verknüpfung des  <code>c<sub>in</sub>
            </code>-Einganges des <em>n</em> -ten Addierers mit dem <code>c<sub>out</sub>
            </code>-Ausgang des vorhergehenden <em>n-1</em> -tenVolladdierers entsteht die in <illustrationLink ref="RCA"/> dargestellte Rechenwerkkomponente zur Berechnung n-stelliger Binärzahlen.<br/>Zur Initialisierung der Übertragsbehandlung wird der Eingangsübertrag für den ersten Volladdierer mit 0 vorbelegt.</p>
         <illustration id="cpu" width="561" caption="Ripple-Carry-Adder" gfx="sysarch/RCA.png"/>
         <p>Es ist keine zwingende Voraussetzung, daß alle Rechenoperationen, die von einer ALU bereitgestellt werden vollständig in Hardware realisiert sind. Durch die Verwendung von Mikroprogrammen können diese selbst durch Programme implementiert sein.</p>
         <subsubtopic>Leitwerk (CU)</subsubtopic>
         <p>Dem Leitwerk obliegt die Steuerung des gesamten Verarbeitungsflusses. Hierzu zählen insbesondere die Versorgung der ALU mit Berechnungsaufgaben durch Bereitstellung der benötigen Befehle und Operanden.</p>
         <p>Zur Regelung der Verarbeitung speichert das Leitwerk prozessorinterne Zustände (Status von Berechnungen (wie Überläufe, Ergebnis Null) und Fehlerindikatoren) in CPU-internen Speicherbereichen, den sog. Registern.</p>
         <subsubtopic>Registersatz</subsubtopic>
         <p>Der Registersatz wird durch eine Reihe von Speicherzellen, die direkt in der CPU untergebracht sind realisiert. Diese Speicherform stellt die schnellste (der Zugriff geschieht im Rahmen eines Prozessortaktzyklus) und gleichzeitig teuerste (daher stehen in der Regel in Summe nur wenige Byte zur Verfügung) dar.</p>
         <p>Register besitzen typischerweise eine feste Bitlänge, die mit der verarbeitbaren Wortlänge der CPU in engem Zusammenhang steht. Üblich sind 8-, 16-, 32- und 64-Bit Register sowie 40- und 80-Bit Register für Spezialanwendungen (Fließkommaberechung).</p>
         <p>Häufig werden die zur Verfügung stehenden Register bezüglich ihrer Funktionsweise, d.h. ihres Einsatzgebietes unterschieden, da oftmals nicht in jedem Register Operanden für beliebige Maschineninstruktionen zur Verfügung gestellt werden können.</p>
         <p>Minimalanforderung an einen Registersatz ist die Bereitstellung eines Befehlszeigerregisters (engl. <em>
               <keyword>Instruction Pointer Register</keyword>
            </em>), welches die Adresse des nächsten abzuarbeitenden Befehls enthält.<br/>Darüberhinaus sind Register zur Aufnahme der Speicheradressen der zentralen Datenstrukturen (z.B. Stack) üblich.</p>
         <p>Beispielsweise partitioniert die Intel-Pentium-Architektur (<a href="http://en.wikipedia.org/wiki/IA-32">IA-32</a>) den verfügbaren Registersatz in vier Bereiche:</p>
         <ul>
            <li>Allzweck (engl. <em>General-purpose</em>) Register:<br/>Acht Register zur Aufnahme von Operanden und Speicheradressen.<ul>
                  <li>EAX: Akkumulator zur Speicherung von Operanden und Ergebnisdaten.</li>
                  <li>EBX: Zeiger auf Daten im DS-Segment.</li>
                  <li>ECX: Zählregister für Schleifen und Zeichenkettenmanipulationen.</li>
                  <li>EDX: Zeiger auf Ein-/Ausgabedaten.</li>
                  <li>ESI: Zeiger in das durch DS bezeichnete Datensegment. Quellzeiger für Zeichenkettenoperationen.</li>
                  <li>EDI: Zeiger in das durch ES bezeichnete Datensegment zur Aufnahme von Zieldaten (typischerweise für Zeichenkettenoperationen verwendet.</li>
                  <li>ESP: Zeiger auf das oberste Element des Stacks, der durch das SS-Register bezeichnet wird.</li>
                  <li>EBP: Zeiger auf das unterste Element des Stacks, der durch das SS-Register bezeichnet wird.</li>
               </ul>
            </li>
            <li>Segment Register:<br/>Identifizieren Speicherbereiche.<ul>
                  <li>DS, ES, FS, GS: Datensegmente, die Ein-/Ausgabedaten enthalten.</li>
                  <li>SS: Stack Segment.</li>
               </ul>
            </li>
            <li>Status- und Kontrollregister:<br/>Speichern Aussagen über verschiedene CPU interne Status.<ul>
                  <li>CF (Carry Flag): Gesetzt falls bei einer arithmetischen Operation ein Über- oder Unterlauf auftritt.</li>
                  <li>PF (Parity Flag): Gesetzt falls das niedersignifikante Byte eines Resultats eine geradzahlige Anzahl 1-en enthält.</li>
                  <li>AF (Adjust Flag): Gesetzt falls bei einer Dezimalzahloperation ein Über- oder Unterlauf auftritt.</li>
                  <li>ZF (Zero Flag): Gesetzt falls das Ergebnis einer Berechnung Null ist.</li>
                  <li>SF (Sign Flag): Identisch zum höchstsignifikanten Bit eines Berechnungsergebnisses und damit identisch zum Vorzeichen.</li>
                  <li>OF (Overflow Flag): Gesetzt falls Berechnungsergebnis zu groß oder zu klein für Speicherung ist.</li>
                  <li>DF (Direction Flag): Steuert die Richtung der Stringverarbeitung.</li>
                  <li>IF (Interrupt Enable Flag): Steuert die Reaktion des Prozessors auf maskierbare Unterbrechungen.</li>
                  <li>TF (Trap Flag): Steuert den Eintritt in die Einzelschrittverarbeitung (zur Fehlersuche genutzt).</li>
                  <li>IOPL (IO Privilege Level): Bitfeld, welches die Ein-/Ausgabeprivilegien eines Prozesses festlegen.</li>
                  <li>NT (Nested Task Flag): Gesetzt falls aktuell verarbeitete Task mir vorhegend verarbeiteter in Verbindung steht.</li>
                  <li>RF (Resume Flag): Steuert Reaktion der CPU auf Debug-Ausnahmen.</li>
                  <li>VM (Virtual Mode): Steuert Eintritt in den virtuellen 8086-Modus.</li>
                  <li>AC (Alignment Flag): Aktiviert (in Verbindung mit dem <code>AM</code>-Bit des Kontrollregisters <code>CR0</code>) die Bereichsprüfung für Speicherreferenzen.</li>
                  <li>ID (Identification Flag): Weist auf Unterstützung des <code>CPUID</code>-Befehls hin.</li>
               </ul>
               <li>
                  <a name="PC">Befehlszeiger</a> .<br/>Das <code>EIP</code>-Register enthält einen 32-Bit langen Verweis auf die nächste auszuführende Instruktion.</li>
            </li>
         </ul>
         <p>Die durch eine CPU angebotenen Befehle können (wie im Falle des Ripple-Carry-Addierers gezeigt) festverdrahtet sein, oder selbst durch kleine in der CPU abgelegte Programme -- sog. <em>Mikroprogramme</em> -- realisiert sein.</p>
         <p>Eine ausführliche Fallstudie zur IA-32- und IA-64-Architektur findet sich in <a href="index.html#maertin">[Mär01, S. 174ff.]</a>
         </p>
         <subsubtopic>Mikroprogramm</subsubtopic>
         <p>Das Konzept der Mikroprogrammierung, d.h. Einzelbefehle in eine Reihe von<keyword>Mikrooperationen</keyword>aufzuteilen, wurde kommerziell erstmals im IBM-System 360 verwirklicht. Seine Wurzeln reichen jedoch noch in die Zeit der Vorgängermaschine 1620 zurück, die bereits durch geschickte Speicheroperationen eine Änderung des Befehlssatzes ermöglichte (<a href="index.html#ceruzzi">[Cer03, S. 107]</a>).</p>
         <p>Die Existenz von Mikrooperationen ist ein zentrales Kennzeichen einer CISC-Architektur.</p>
      </region>
      <region numbered="yes">
         <topic name="RA">Rechnerarchitekturen</topic>
         <subtopic>Befehlsarchitekturen</subtopic>
         <p>Die Architektur des Befehlssatzes, d.h. sein Aufbau und Umfang, bestimmt die Schnittstelle zur direkten Interaktion mit der CPU-Hardware welche typischerweise durch maschinell übersetzte (compilierte) Betriebssysteme und Anwendungsprogramme direkt bedient wird.</p>
         <p>Die maschinelle Bedienung dieser Schnittstelle kann durch vielfälltige Softwarekomponenten erfolgen.<br/>
            <illustrationLink ref="compExe"/> stellt drei in der Praxis bedeutsame Ansätze gegenüber.</p>
         <illustration id="compExe" width="600" caption="Übersetzungs- und Ausführungstechniken" gfx="sysarch/uebersetzung.png"/>
         <p>Im linken Bildbereich ist das Zusammenspiel einer ausschließlich interpretierenden Ausführungsumgebung dargestellt. Eine solche akzeptiert ein Quellprogramm als Eingabe und führt dieses<gerquot>direkt</gerquot>, d.h. ohne expliziten Übersetzerlauf, aus. Die notwendige Transformation der Hochspracheninstruktionen in die von der CPU unterstützten Befehle wird dynamisch zur Laufzeit vorgenommen.</p>
         <p>Der mittlere Bereich stellt die klassischen Entwicklungsschritte unter Verwendung eines CPU-spezifischen (d.h. plattformspezifischen) Übersetzers dar, der maschinenspezifischen Assemblercode erzeugt, der vermöge eines Assemblierers in direkt (nativ) ausführbaren Binärcode übersetzt wird.</p>
         <p>Als Beispiel seien die im Verlauf der Übersetzung eines C-Programmes entstehenden Artefakte angeführt.</p>
         <p>Quellcode:</p>
         <code>
            <pre>#include &lt;stdio.h&gt;
                int main(int argc, char** argv) {
                    printf("hello world");
                    return 0;
                }</pre>
         </code>
         <p>Erzeugter Assembler-Code für die Intel-Architektur</p>
         <code>
            <pre>section .data
hello:     db 'hello world',10
helloLen:  equ $-hello
section .text
global _start
_start:
    mov eax,4
    mov ebx,1
    mov ecx,hello
    mov edx,helloLen
    int 80h
    mov eax,1
    mov ebx,0
    int 80h</pre>
         </code>
         <p>Der Quellcode eines Assemblerprogrammes kann vergleichsweise einfach in binären Maschinencode übersetzt werden, da jede dort auftretende mnemonische Anweisung eineindeutig auf eine maschinenspezifische Instruktion abgebildet werden kann.</p>
         <p>Ausführbare Binärdatei:</p>
         <illustration id="hwelf" width="600" caption="Ausführbare Binärdatei (hexadezimale Ansicht)" gfx="sysarch/hwelf.png"/>
         <p>Darüberhinaus hat der in der Graphik der <illustrationLink ref="compExe"/> rechts dargestellte Ansatz der hybriden Übersetzung durch die Popularität von Programmiersprachen wie Java oder C# in jüngerer Zeit eine große Anhängerschaft erworben.</p>
         <p>Bei dieser Vorgehensweise wird der Quellcode in ein Zwischenformat, den sog. Intermediärcode oder Bytecode, übersetzt, der dann durch einen als <em>Virtuelle Maschine</em> bezeichneten Interpreter zur Laufzeit in reale Maschineninstruktionen der Zielhardware umgesetzt wird.</p>
         <p>Grundsätzliches Unterscheidungsmerkmal der Abarbeitung des entstehenden Maschinencodes ist die Realisierung des Instruktionssatzes. Hierbei wird zwischen CISC-, RISC- und VLIW-Varianten unterschieden, die jeweils in der Realisierung des Befehlsvorrates und der Umsetzung des Befehlsformates differieren..</p>
         <subsubtopic>CISC-Befehlssatzarchitekturen</subsubtopic>
         <p>Architekturen, die viele und hochdifferenzierte Instruktionen für vielfältige Problemstellungen anbieten werden als <em>
               <keyword>Complex Instruction Set Computing</keyword>
            </em> (kurz: <a href="http://de.wikipedia.org/wiki/CISC">
               <keyword>CISC</keyword>
            </a>) bezeichnet.</p>
         <p>Die Ursprünge der CISC-Architekturen reichen bis in die Zeit der Großrechner in den 1960er Jahren zurück. Damals erwies sich die Mikroprogrammierung als probates Mittel der Komplexitätsreduktion bei der Planung und Umsetzung der verarbeitenden CPUs. Überdies bargen die im ROM des Zentralprozessors abgelegten Umsetzungen mächtiger Befehle einen Geschwindigkeitsvorteil, da auf die CPU-internen Speicherbereiche in deutlich performanterer Zugriff realisiert werden konnte, als dies für die damals üblichen Ferritkern-Hintergrundspeicher erzielbar gewesen wäre.</p>
         <p>Ziel der Schaffung von Instruktionssätzen mit meheren Hundert verschiedenen (300-400 verschiedene Instruktionstypen sind keine Seltenheit) Befehlen war es die semantische Lücke zwischen den zur Applikationsprogrammierung eingesetzten Hochsprachen und den realen Maschineninstruktionen möglichst schmal zu halten. (<a href="index.html#maertin">[Mär01, S. 156f.]</a>)</p>
         <p>Gleichzeitig verfügen CISC-Architekturen über eine Reihe verschiedender Befehlsformate, die sich in ihrem internen Aufbau unterscheiden. Im Kern bestehen Befehlsworte immer aus der Spezifikation der auszuführenden Maschineninstruktion, den benötigen Operanden und der Angabe des Speicherplatzes für das Berechnungsergebnis. Teilweise können die Eingangsoperanden direkt im Befehl untergebracht werden, statt sie aus einem Register oder einer Speicherzelle zu laden. Operanden dieses Typs werden als <em>Immediate Operanden</em> bezeichnet.<br/>Im Falle von Verzweigungsbefehlen enthält der Operand die Adresse der nächsten auszuführenden Instruktion.</p>
         <p>Als Konsequenz des komplexen Befehlsaufbaus und der mächtigen angebotenen Funktionalität kann die Abarbeitung eines CISC-Befehls mehere Taktzyklen in Anspruch nehmen.</p>
         <illustration id="intelIF" width="600" caption="Instruktionsformat der Intel IA-32-Architektur" gfx="sysarch/intelif.png"/>
         <p>
            <small>Abbildung: Intel Architecture Software Developer's Manual Vol. 2, S. B-1</small>
         </p>
         <p>
            <illustrationLink ref="intelIF"/> illustriert beispielhaft das Instruktionsformat der Intel IA-32-Architektur. Es stellt den binären Opcode eines Befehls wahlweise durch ein (z.B. <code>ADD</code>, <code>XOR</code>, <code>CMP</code>) oder zwei Byte (z.B. <code>MOVZX</code>, <code>CMPXCHG</code>, <code>XADD</code>) dar, die von einigen Befehlen (z.B. <code>MUL</code>, <code>DIV</code>, <code>NEG</code>) durch die in den Bits 3-5 des ModR/M-Bytes untergebrachten Erweiterungsfelder zusätzlich ergänzt werden.<br/>Grundsätzlich legt das ModR/M-Byte den Adressierungsmodus eines Befehls fest, d.h. welche Register angesprochen werden (Reg-Feld) oder ob eine vorzeichenbehafte Verarbeitung vorgenommen wird.</p>
         <p>Als Beispiel eines Mikroprogrammes sei die Realisierung der Operation <code>CMPXHG8B</code>auf der Intel-Pentium-Hardware angeführt.<br/>Die genannte Operation vergleicht den Inhalt einer 64-Bit Speicherzelle mit dem der Kombination der Register EDX und EAX. Sind die beiden Inhalte gleich, so wird der Registerinhalt aus ECX:EBX in die Speicherzelle transferiert, andernfalls der Speicherzelleninhalt in die Register geladen.<br/>Das hierfür nötige Mikroprogramm lautet (Pseudocode, Pfeile deuten einzelne Speichertransferoperationen an):</p>
         <code>
            <pre>IF(EDX:EAX = DEST)
                ZF &lt;-- 1
                DEST &lt;-- ECX:EBX
                ELSE
                ZF &lt;-- 0
                EDX:EAX &lt;-- DEST</pre>
         </code>
         <p>Bedingt durch die breite Verfügbarkeit schneller Hintergrundspeicher und die zunehmende Komplexität in der Erstellung der benötigten Mikroprogramme, sowie die Zunahme der zur Speicherung benötigten Chipfläche bedingte den zunehmenden Wechsel zu Befehlssätzen, deren Mächtigkeit und Umfang gegenüber dem CISC-Ansatz deutlich reduziert ausfällt.</p>
         <p>
            <b>Exkurs</b>: Komplexitätsprobleme CISC-Architekturen: der Pentium FDIV-BUG</p>
         <ul>
            <li>
               <a href="http://kuhttp.cc.ukans.edu/cwis/units/IPPBR/pentium_fdiv/pentgrph.html">Empirische Untersuchung der Häufigkeit des Fehlerauftretens</a>
            </li>
            <li>
               <a href="http://support.intel.com/support/processors/pentium/fdiv/wp/">Statistical Analysis of Floating Point Flaw</a>
            </li>
         </ul>
         <p>Daher integrieren vormals ausschließlich als CISC ausgelegte CPU-Familien (z.B. Intel x86, DEC-VAX) zunehmen Elemente alternativer Befehlssatzarchitekturen.</p>
         <subsubtopic>RISC-Technik</subsubtopic>
         <p>Grundidee des <em>
               <keyword>Reduced Instruction Set Computing</keyword>s</em> (<keyword>RISC</keyword>) ist es eine Komplexitätsreduktion der CPU zur Minimierung des Umfanges des angebotenen Befehlssatzes und gleichzeitig dessen Befehlsformaten herbeizuführen.</p>
         <p>Typische RISC-Prozessoren (wie MIPS R10000, Sun-SPARC, DEC-Alpha, Power PC) bieten daher oftmals nur ca. 50 verschiedene Befehle an, deren interne Realisierungskomplexität so stark reduziert ist, daß sie vollständig in Hardware und damit genau einem Prozessortaktyklus abgearbeitet werden können. Eine Nebenbedingung hierfür bildet die Beschränkung der in einer Maschineninstruktion zugelassenen Speicherzugriffe. So gestatten RISC-Architekturen üblicherweise lediglich Operationen auf registerresidenten Operanden, um aufwendige Speicherzugriffe zu umgehen.</p>
         <p>Alle Elemente des Befehlssatzes eines RISC-Prozessors besitzen, unabhängig von der Wortbreite des verarbeitenden Prozessors, dieselbe Wortlänge und einen einheitlichen Aufbau.<br/>Ausgehend hiervon vereinfacht sich der interne Prozessoraufbau und die Befehlsverarbeitung dramatisch, da keine Mikroprogramm-Unterstützung und flexible Decodierung der Befehlsworte benötigt wird. Überdies bieten RISC-Architekturen lediglich eine stark reduzierte Befehlszahl an, die nur basale Instruktionen umfaßt.</p>
         <p>Als Konsequenz dieses Reduktionsvorganges umfassen für RISC-Architekturen ausgelegte Maschinenprogramme typischerweise eine signifikant größere Anzahl Instruktionen als deren CISC-Pendant, da die RISC-Architektur die Explizierung komplexer Anweisungen auf der Maschinensprachenebene bedingt.<br/>Aufgrund des vereinfachten Prozessoraufbaus können RISC-Rechner jedoch gleichzeitig eine geringer Zykluszeit (d.h. höhere Taktfrequenz) realieren, weshalb die in der Regel in einem Prozessorzyklus abgearbeiteten umfangreicheren Befehlsfolgen mit gegenüber der CISC-Architektur höherem Durchsatz umgesetzt werden können.</p>
         <p>Die durch RISC-Technik erzielbare Steigerung der Verarbeitungsgeschwindigkeit wird durch die erreichbare Zykluszeit physikalisch begrenzt. Um dennoch eine weitere Skalierung zu ermöglichen werden seit den 1980er Jahren instruktionsparallele Ansätze verstärkt untersucht und auch in kommerziellen CPUs angeboten.</p>
         <subsubtopic name="ILP">Expliziter Parallelismus und EPIC/VLIW</subsubtopic>
         <p>Architekturen mit explizitem Parallelismus auf Maschinenwortebene, sog. <em>Instruktionsebenenparallelität</em>,   erlauben die simulatane Verarbeitung mehr als eines Maschinenbefehls zu einem Zeitpunkt.<br/>Voraussetzung dieser Architekturform ist die Präsenz mehrer eigenständiger Rechenwerke, beispielsweise separater ALU-Einheiten für Integer- und Gleitkommaberechnung.</p>
         <p>Grundlage dieser Befehlssatzarchitekturen ist die massive Erweiterung des verarbeiteten Maschinenwortes zum <em>
               <keyword>Very Large Instruction Word</keyword>
            </em> (<keyword>VLIW</keyword>), das je nach Rechnertyp bis zu 128-Bit lange Instruktionsworte (z.B. Intels IA-64-Architektur ( <illustrationLink ref="EPIC"/> )) anbieten kann.<br/>Begründet durch die bereits auf maschineninstruktionsebene explizierte Parallelität der Einzelinstruktionen findet sich verschiedentlich auch der durch den Hersteller          <name>Intel</name> eingeführte Begriff des <em>
               <keyword>Explicit Parallel Instruction Computing</keyword>s</em> (<keyword>EPIC</keyword>).</p>
         <illustration id="EPIC" width="607" caption="Instruktionsformat der Intel IA-64-Architektur" gfx="sysarch/epicif.png"/>
         <p>Der in <illustrationLink ref="EPIC"/> dargestellte Aufbau der IA-64-Befehlsworte zeigt die Realisierung einer typischen VLIW-Instruktion. Jedes Befehlswort besteht aus höchstens drei eigenständigen Instruktionen, die jeweils durch 41-Bit lange (Sub-)Instruktionsworte codiert werden. Das als <em>template</em> bezeichnete Bitfeld regelt für jedes VLIW-Instruktionswort separat die Zuordnung der Subinstruktionsworte zu den verfügbaren Recheneinheiten bzw. spezifiziert deren Verarbeitungsnatur näher. Folgende Instruktionstypen werden unterschieden.</p>
         <ul>
            <li>
               <u>A</u>LU-Operationen</li>
            <li>
               <u>I</u>nteger-Operationen</li>
            <li>
               <u>M</u>emory-Zugriffe</li>
            <li>
               <u>F</u>ließkommaberechnungen</li>
            <li>
               <u>B</u>ranches (Sprunganweisungen)</li>
         </ul>
         <p>Grundsätzlich sind nicht alle kominatorisch möglichen Zusammensetzungen zugelassen. So darf beispielsweise das <em>slot 2</em> Instruktionswort spezifikationsgemäß nicht mit einem Speicherzugriff (M) bestückt werden.<br/>Die Realisierung des Parallelismus, durch geeignete Zusammensetzung der VLIW-Worte, obliegt generell dem Übersetzer, d.h. sie wird bereits vor der tatsächlichen Ausführungszeit fixiert. Der Programmübersetzungsprozeß nimmt daher -- aufgrund des zu leistenden gesteigerten Optimierungsaufwandes -- zusätzliche Zeit in Anspruch und erfordert speziell auf die Zielhardware angepaßte Übersetzer.</p>
         <p>VLIW/EPIC-basierte Ansätze können, bei geeigneten -- d.h. gut parallelisierbaren -- Problemstellungen, große Geschwindigkeitszuwäche entfalten. Ist ein Instruktionsebenenparallelismus jedoch aufgrund von starken <a href="#dataHaz">Datenabhängigkeiten</a> (beispielsweise wenn jede Instruktion ein durch die jeweilige Vorgängerinstruktion berechnetes (Teil-)Ergebnis als Eingabe erwartet) nicht möglich, so werden müssen viele Subinstruktionsworte durch Leeroperationen (<code>NOP</code>) aufgefüllt werden und die durch sie ansprechbaren Funktionseinheiten bleiben ungenutzt.</p>
         <p>Grundsätzlich lassen sich Befehlsfolgen ohne <a href="#abh">Abhängigkeiten</a> , wie nebenläufig auszuführende Threads sehr effizient in VLIW-Instruktionsworte.</p>
         <scriptElement type="links" title="Weiterführende Links">
            <link>
               <a href="http://www.cc.gatech.edu/services/unisys-folklore/">Univac History</a>
            </link>
            <link>
               <a href="http://inventors.about.com/library/weekly/aa062398.htm">The History of the UNIVAC Computer</a>
            </link>
            <link>
               <a href="http://www.fourmilab.ch/documents/univac/">UNIVAC Memories</a>
            </link>
            <link>
               <a href="http://www2.latech.edu/~acm/helloworld/IBM1401.html">Hello-World-Programm auf IBM 1401</a>
            </link>
            <link>
               <a href="http://www.multicians.org/">MULTICS</a>
            </link>
            <link>
               <a href="http://home.t-online.de/home/cyrill.cmk/">Computer Model Katalog</a>
            </link>
            <link>
               <a href="http://www.iwi.uni-hannover.de/diplwww/bode/data/1.htm">Rechner_ und Betriebssystemgenerationen und deren Auswirkungen auf betriebliche Anwendungssysteme</a>
            </link>
            <link>
               <a href="http://www.intel.com/research/silicon/mooreslaw.htm">
                  <name>Moore</name> s Gesetz</a>
            </link>
            <link>
               <a href="http://www.scompt.com/school/computer_architecture/64-bit_computing.pdf">Two Approaches to 64-Bit Computing</a>
            </link>
         </scriptElement>
         <subtopic name="mikroarch">Mikroarchitekturen</subtopic>
         <p>Parallel zum Übergang von CISC- zu RISC-basierten Befehlsarchitekturen und der zunehmenden Verbreitung von auf dem VLIW-Ansatz aufbauenden Prozessoren werden neue Leistungspotentiale auch immer mehr durch neue Konzepte auf der Mikroebene erschlossen. Diese Ebene ist hierbei unterhalb der Abarbeitung der einzelnen Instruktionen der Befehlsarchitektur angesiedelt und widmet sich ausschließlich der internen Realisierung der Verarbeitung einer einzelnen Maschineninstruktion.</p>
         <subsubtopic name="pipelineing">Phasen-Pipelining</subsubtopic>
         <p>Insbesondere bei RISC-Architekturen, die sich zum Ziel setzen jede Maschineninstruktion in Schnitt in genau einem Taktzyklus abarbeiten, definieren die physikalischen Signallaufzeiten eine Obergrenze des Prozessortaktes, da in einem Takt nicht beliebig viele logische Operationen ausgeführt werden können.<br/>Um dennoch die Verarbeitungsgeschwindigkeit einerseits und gleichzeitig die Auslastung der verschiedenen Prozessorkomponenten andererseits zu erhöhen etablierten sich <em>
               <keyword>Phasen-Pipeline-Architektur</keyword>en</em>.  Grundansatz dieses Miroarchitekturtyps ist es, jeden Einzelbefehl in eine Reihe fein granulierter Mikroinstruktionen aufzuspalten und diese durch jeweils durch separate CPU-Komponenten abzuarbeiten. Als Resultat können gleichzeitig Befehle verschiedener Ausführungsphasen verarbeitet werden. Die hierbei abzuarbeiten Einzelverarbeitungsschritte sind in jedem Falle von deutlich geringerer Schaltungskomplexität als vollständige Befehlsverarbeitungen.</p>
         <illustration id="pipe" width="600" caption="Schema einer sechsstufigen Phasen-Pipeline" gfx="sysarch/pipeline.png"/>
         <p>
            <a name="phases">Abbildung</a>
            <illustrationLink ref="pipe"/> illustriert den Aufbau einer sechsstufigen Phasen-Pipeline. Ihre Nutzung setzt voraus, daß die Ausführung jedes Maschinenbefehls in die sechs dargestellten Phasen eingeteilt wird:</p>
         <ul>
            <li>
               <em>Befehlsholphase</em> (IF)<br/>Der nächste auszuführende Maschinenbefehl wird durch das Leitwerk in die ALU geladen. Anschließend wird der Befehlszähler erhöht.</li>
            <li>
               <em>Befehlsdecodierphase</em> (DE)<br/>Die für den geladenen Maschinenbefehl auszuführenden Mikroprogramm-Operationen werden ermittelt.</li>
            <li>
               <em>Operandenholphase</em> (OF)<br/>Die zur Befehlsausführung benötigten Eingangsdaten (Operanden) werden geladen.</li>
            <li>
               <em>
                  <a href="#EX">Befehlsausführungsphase</a>
               </em> (EX)<br/>Durch Befehlsausführung wird das Ergebnis berechnet.</li>
            <li>
               <em>Speicherrückschreibphase</em> (MEM)<br/>Berechnungsergebnisse werden in Speicher zurückgeschrieben.</li>
            <li>
               <em>Befehlsrückschreibphase</em> (WB)<br/>Das Berechnungsergebnise werden in Register zurückgeschrieben.</li>
         </ul>
         <p>Wird der Füllungsgrad der Phasen-Pipleline betrachtet, so fällt auf, daß jede Pipeline erst nach einer gewissen Anzahl Takten Ergebnisse liefert. Wird für jede Phase eine Ausführungszeit von genau einem Taktzyklus unterstellt, so ist die <em>Einschwingphase</em> identisch zur Pipelinelänge. Daher liefert die Pipleline der <illustrationLink ref="pipe"/> ihr erstes Ergebnis erst nach sechs Takten.<br/>Alle darauffolgenden Takte wird jedoch im Idealfalle ein weiteres Ergebnis produziert.</p>
         <p>Der maximale Auslastungsfall, der in jedem Taktzyklus ein Ergebnis berechnet, kann jedoch nur erreicht werden, wenn ein gleichmäßiger Füllungsgrad der Pipleline vorliegt, d.h. alle Pipelinestufen befüllt sind. Dies setzt jedoch voraus, daß keine Datenabhängigkeiten zwischen den verarbeiteten Einzelbefehlen bestehen, da zu Auslastungslücken führen können.</p>
         <p>Solche Auslastungslücken (sog. <em>
               <keyword>pipeline bubble</keyword>s</em>) treten dann auf, wenn bestimmte Abhängigkeitssituationen (sog. <em>
               <keyword>pipeline hazard</keyword>s</em>) gegeben sind, die eine effiziente Nutzung der Pipeline verhindern.</p>
         <p>
            <a name="abh">Typischerweise</a> werden drei Typen von Pipeline Hazards unterschieden:</p>
         <ul>
            <li>
               <b>
                  <a href="http://www.cs.iastate.edu/~prabhu/Tutorial/PIPELINE/structHaz.html">Ressourcen Abhängigkeit</a>
               </b>treten dann auf, wenn nicht alle Phasen beliebig überlappend ausgeführt werden können.</li>
            <li>
               <b>
                  <a href="http://www.cs.iastate.edu/~prabhu/Tutorial/PIPELINE/dataHaz.html">Datenabhängigkeit</a>
               </b>treten dann auf, wenn eine Instruktion das Ergebnis der direkt vorhergehenden als Eingangsoperand benötigt.</li>
            <li>
               <b>
                  <a href="http://www.cs.iastate.edu/~prabhu/Tutorial/PIPELINE/controlHaz.html">Kontrollflußabhängigkeit</a>
               </b>treten dann auf, wenn die Verarbeitung einer Instruktion durch Modifikation des <a href="#PC">Befehlszeigers</a> einen anderen als den bereits in der Pipeline befindlichen als nächste auszuführende Instruktion wählt.</li>
         </ul>
         <scriptElement type="example" name="structHaz" title="Ressourcen Abhängigkeit">
            <tabular>
               <head length="10">
                  <column title="Instruktion"/>
                  <column style="text-align:center" colspan="5" title="Taktzyklus"/>
               </head>
               <body>
                  <row>
                     <cell/>
                     <cell>1</cell>
                     <cell>2</cell>
                     <cell>3</cell>
                     <cell>4</cell>
                     <cell>5</cell>
                     <cell>6</cell>
                     <cell>7</cell>
                     <cell>8</cell>
                     <cell>9</cell>
                  </row>
                  <row>
                     <cell>I<sub>1</sub>
                     </cell>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell style="color:red">MEM</cell>
                     <cell>WB</cell>
                  </row>
                  <row>
                     <cell>I<sub>2</sub>
                     </cell>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell>MEM</cell>
                     <cell>WB</cell>
                  </row>
                  <row>
                     <cell>I<sub>3</sub>
                     </cell>
                     <cell/>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell>MEM</cell>
                     <cell>WB</cell>
                  </row>
                  <row>
                     <cell>I<sub>4</sub>
                     </cell>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell>MEM</cell>
                     <cell>WB</cell>
                  </row>
                  <row>
                     <cell>I<sub>5</sub>
                     </cell>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell style="color:red">IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell>MEM</cell>
                  </row>
               </body>
            </tabular>
         </scriptElement>
         <p>Beispiel <scriptRef type="example" name="structHaz"/> zeigt als Beispiel einer Ressourcenabhängigkeit den Zustand der sechsstufigen Beispielpipeline, der im Falle nur genau eines Busses (oder nur genau einer Kontrolleinheit) zum Speicherzugriff eintritt. Hierbei kann die <em>Befehlsholphase</em> nicht überlappend mit der <em>Speicherrückschreibphase</em> ausgeführt werden.</p>
         <p>Zur Lösung dieses Problems werden Warteanweisungen (NOP) in die Pipeline eingesteuert, während der die Verarbeitung in der betreffenden Stufe ruht.</p>
         <p>Das Ergebnis ist in Abbildung<scriptRef type="example" name="structHazLsg"/> dargestellt. Auffallend ist hierbei, daß selbst nach Einfügen einer NOP-Operation der Befehlsholvorgang für die Instruktion <code>I<sub>5</sub>
            </code>nicht durchgeführt werden kann, da sich dieser mit dem Speicherzugriff des 2. in der Berarbeitung befindlichen Befehls überschneiden würde. Daher wird erneut ein Wartezyklus eingefügt und die Verarbeitung der 5. Instruktion verzögert.<br/>Dieser Vorgang wiederholt sich bis im 9. Verarbeitungstakt keine Überlappung zwischen Befehlsholphase und Speicherrückschreibphase mehr auftritt.</p>
         <scriptElement type="example" name="structHazLsg" title="Auflösung der Ressourcen-Abhängigkeit">
            <tabular>
               <head length="10">
                  <column title="Instruktion"/>
                  <column style="text-align:center" colspan="5" title="Taktzyklus"/>
               </head>
               <body>
                  <row>
                     <cell/>
                     <cell>1</cell>
                     <cell>2</cell>
                     <cell>3</cell>
                     <cell>4</cell>
                     <cell>5</cell>
                     <cell>6</cell>
                     <cell>7</cell>
                     <cell>8</cell>
                     <cell>9</cell>
                  </row>
                  <row>
                     <cell>I<sub>1</sub>
                     </cell>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell>MEM</cell>
                     <cell>WB</cell>
                  </row>
                  <row>
                     <cell>I<sub>2</sub>
                     </cell>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell style="color:red">MEM</cell>
                     <cell>WB</cell>
                  </row>
                  <row>
                     <cell>I<sub>3</sub>
                     </cell>
                     <cell/>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell style="color:red">MEM</cell>
                     <cell>WB</cell>
                  </row>
                  <row>
                     <cell>I<sub>4</sub>
                     </cell>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell style="color:red">MEM</cell>
                     <cell>WB</cell>
                  </row>
                  <row>
                     <cell>(I<sub>5</sub>-I)</cell>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell style="color:#96db7f">NOP</cell>
                     <cell style="color:red">IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                  </row>
                  <row>
                     <cell>(I<sub>5</sub>-II)</cell>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell style="color:#96db7f">NOP</cell>
                     <cell style="color:#96db7f">NOP</cell>
                     <cell style="color:red">IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                  </row>
                  <row>
                     <cell>(I<sub>5</sub>-III)</cell>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell style="color:#96db7f">NOP</cell>
                     <cell style="color:#96db7f">NOP</cell>
                     <cell style="color:#96db7f">NOP</cell>
                     <cell style="color:red">IF</cell>
                     <cell>DE</cell>
                  </row>
                  <row>
                     <cell>I<sub>5</sub>
                     </cell>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell style="color:#96db7f">NOP</cell>
                     <cell style="color:#96db7f">NOP</cell>
                     <cell style="color:#96db7f">NOP</cell>
                     <cell style="color:#96db7f">NOP</cell>
                     <cell>IF</cell>
                  </row>
               </body>
            </tabular>
         </scriptElement>
         <p>Beispiel <scriptRef type="example" name="dataHaz"/> zeigt den Fall einer Datenabhängigkeit, die durch den Verarbietungsversuch des Ergebnisses der Addition durch die nachfolgende Subtraktion entsteht.</p>
         <scriptElement type="example" name="dataHaz" title="Datenabhängigkeit">
            <tabular>
               <head length="10">
                  <column title="Instruktion"/>
                  <column style="text-align:center" colspan="5" title="Taktzyklus"/>
               </head>
               <body>
                  <row>
                     <cell/>
                     <cell>1</cell>
                     <cell>2</cell>
                     <cell>3</cell>
                     <cell>4</cell>
                     <cell>5</cell>
                     <cell>6</cell>
                     <cell>7</cell>
                  </row>
                  <row>
                     <cell>ADD R1,R2,R3</cell>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell>MEM</cell>
                     <cell>WB</cell>
                  </row>
                  <row>
                     <cell>SUB R4,R5,R1</cell>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell style="color:red">OF</cell>
                  </row>
               </body>
            </tabular>
         </scriptElement>
         <p>Durch Einstreuung von NOP-Befehlen kann die Verarbeitung der Subtraktion solange verzögert werden, bis das Berechnungsergebnis der vorangehenden Addition zur Verfügung steht. So kann die Verarbeitung erst nach drei Wartezyklen mit der Operandenholphase fortgesetzt werden.</p>
         <scriptElement type="example" name="dataHazLsg" title="Lösung der Datenabhängigkeit">
            <tabular>
               <head length="10">
                  <column title="Instruktion"/>
                  <column style="text-align:center" colspan="5" title="Taktzyklus"/>
               </head>
               <body>
                  <row>
                     <cell/>
                     <cell>1</cell>
                     <cell>2</cell>
                     <cell>3</cell>
                     <cell>4</cell>
                     <cell>5</cell>
                     <cell>6</cell>
                     <cell>7</cell>
                  </row>
                  <row>
                     <cell>ADD R1,R2,R3</cell>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell>MEM</cell>
                     <cell>WB</cell>
                  </row>
                  <row>
                     <cell>(SUB R4,R5,R1)</cell>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell style="color:#96db73">NOP</cell>
                  </row>
                  <row>
                     <cell>(SUB R4,R5,R1)</cell>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell style="color:#96db73">NOP</cell>
                     <cell style="color:#96db73">NOP</cell>
                  </row>
                  <row>
                     <cell>(SUB R4,R5,R1)</cell>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell style="color:#96db73">NOP</cell>
                     <cell style="color:#96db73">NOP</cell>
                     <cell style="color:#96db73">NOP</cell>
                  </row>
                  <row>
                     <cell>SUB R4,R5,R1</cell>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell style="color:#96db73">NOP</cell>
                     <cell style="color:#96db73">NOP</cell>
                     <cell style="color:#96db73">NOP</cell>
                     <cell>OF</cell>
                  </row>
               </body>
            </tabular>
         </scriptElement>
         <p>Das Schema des Beispiels<scriptRef type="example" name="contrHaz"/> zeigt eine Datenflußabhängigkeit, die durch den bedingten Sprung <code>JNE</code>(Verzweigung bei Ungleichheit) entsteht. Nach Ausführung des Sprungbefehls muß bei <code>l1</code>fortgesetzt werden. Dies geschieht durch Umsetzen des Befehlszeigers unter Überspringen der auf die <code>JNE</code>-Instruktion folgenden Anweisungen.<br/>Diese sind jedoch bereits in die Phasen-Pipeline geladen und liefern daher die nicht mehr benötigten (rot dargestellten) Ergebnisse.</p>
         <scriptElement type="example" name="contrHaz" title="Kontrollflußabhängigkeit">
            <tabular>
               <head length="10">
                  <column title="Instruktion"/>
                  <column style="text-align:center" colspan="5" title="Taktzyklus"/>
               </head>
               <body>
                  <row>
                     <cell/>
                     <cell>1</cell>
                     <cell>2</cell>
                     <cell>3</cell>
                     <cell>4</cell>
                     <cell>5</cell>
                     <cell>6</cell>
                     <cell>7</cell>
                     <cell>8</cell>
                     <cell>9</cell>
                  </row>
                  <row>
                     <cell>CMP R1,0</cell>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell>MEM</cell>
                     <cell>WB</cell>
                  </row>
                  <row>
                     <cell>JNE l1</cell>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell>MEM</cell>
                     <cell>WB</cell>
                  </row>
                  <row>
                     <cell>...</cell>
                     <cell/>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell>MEM</cell>
                     <cell style="color:red">WB</cell>
                  </row>
                  <row>
                     <cell>...</cell>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell>EX</cell>
                     <cell style="color:red">MEM</cell>
                     <cell style="color:red">WB</cell>
                  </row>
                  <row>
                     <cell>...</cell>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                     <cell>OF</cell>
                     <cell style="color:red">EX</cell>
                     <cell style="color:red">MEM</cell>
                  </row>
                  <row>
                     <cell>l1: ...</cell>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell/>
                     <cell>IF</cell>
                     <cell>DE</cell>
                  </row>
               </body>
            </tabular>
         </scriptElement>
         <p>Die Einsteuerung von NOP-Anweisungen, bzw. das Verwerfen nicht mehr benötigter Ergenisse, garantiert zwar die Korrektheit der berechneten Resultate, setzt jedoch die Leistungsfähigkeit einer Phasen-Pipeline herab.<br/>So erzwingt die restriktive Umsetzung des Speicherzugriffes aus Beispiel<scriptRef type="example" name="structHaz"/> zum Einschub von vier Wartezyklen nach jeweils vier Berechnungsphasen.<br/>Ähnliches gilt für die durch Beispiel<scriptRef type="example" name="dataHaz"/> betrachteten Datenabhängigkeiten. Auch sie können nur durch Einbringung entsprechender Verzögerungen, während der die ALU nicht genutzt wird, aufgelöst werden.<br/>Im Falle der Kontrolfußabhängigkeit werden zwar keine Wartezyklen benötigt, jedoch werden im Verlauf der Verarbeitung durch die Pipeline Ergebnisse berechnet, die nicht benötigt werden, was effektiv einer Zeitverzögerung in der Bereitstellung der tatsächlich gewünschen Resultate gleichkommt.</p>
         <p>
            <b>Phasenpipelines in der Praxis</b>
            <br/>Die Verwendung von Phasenpipelines zur Steigerung des Durchsatzes bei gleichzeitiger Erhöhung der Taktfrequenz hat sich inzwischen breit bei kommerziellen Mikroprozessoren durchgesetzt.<br/>Intel verwendet seit der Pentium-Architektur Piplelining-Techniken, die zuerst eher zaghaft durch die maximal achtstufige Umsetzung in den Pentium-I-CPUs Einzug hielt, jedoch inzwischen mit einer extrem großen 30-stufigen Umsetzung in den Pentium-III-Chips bzw. 20 Stufen beim Pentium-4 ihre Entfaltung findet. Diese<br/>AMD verwendet im 32-Bit Athlon-Prozessor eine 10-stufige Pipeline und bietet in der 64-Bit CPU-Variante eine um zwei zustätzliche Stufen erweiterte Umsetzung an.</p>
         <p>Die ungewöhnlich lange Pipeline der Pentium-III- und -4-Realisierungen zeigt, daß auch große Phasenpipelines effizient eingesetzt werden können und erlauben es die genannten CPUs bei sehr hohen Taktraten zu betreiben.</p>
         <p>Die <illustrationLink ref="P5Pipe"/> zeigt die Realisierung der ersten Generation der Pentium-Mikroarchitektur, welche über eine zweifach gegabelte Pipeline verfügt. Die Architektur verfügt über drei parallel angeordnete Pipelines, wovon die als<gerquot>U-</gerquot>und<gerquot>V-Pipeline</gerquot>bezeichneten jeweils zur Verarbeitung von ganzzahligen Ausdrücken dienen. Zusätzlich zweigt die Ausführungsphase (EX) der U-Pipeline in die FP-Pipeline ab, welche vier zusätzliche Stufen zur Verarbeitung von Fließkommainstruktionen bereitstellt.<br/>Neben den <a href="#phases">bereits bekannten</a> Pipelinephasen zeigt die Graphik die zusätzlichen Ausführungsphasen <code>X1</code>und <code>X2</code>, sowie die gesonderte Rückschreib- (<em>Write Float</em> (WF)) und Fehlerbehandlungsphase (<em>Error Handling</em> (ER)) für Fließkommawerte.</p>
         <illustration id="pentPipe" width="572" caption="Aufbau der Pentium-I-Phasen-Pipeline" gfx="sysarch/pentPipe.png"/>
         <p>Durch die extrem langen Pipelines gängiger Prozessoren werden sehr hohe Anforderung an die adäquate Bereitstellung der zu verarbeitenden Instruktionen gestellt, da sich Pipelinekonflikte mit gravierenden Performanceeinbußen auswirken können.<br/>Aus diesem Grunde führen <em>superskalare</em> Architekturen eine Reihe von Maßnahmen zur Verbesserung der Pipelineauslastung ein.</p>
         <scriptElement type="links" title="Weiterführende Links">
            <link>
               <a href="http://www.cs.iastate.edu/~prabhu/Tutorial/PIPELINE/hazards.html">Pipeline Hazards</a>
            </link>
            <link>
               <a href="http://www.anandtech.com/cpu/showdoc.html?i=1956&amp;p=2">Pipelinling 101</a>
            </link>
            <link>
               <a href="http://www.tomshardware.com/cpu/20001120/p4-09.html#hyper_pipeline">Pentium-4-Hyper-Pipeline</a>
            </link>
            <link>
               <a href="http://arstechnica.com/cpu/01q2/p4andg4e/p4andg4e-3.html">The perils of deep pipelining</a>
            </link>
            <link>
               <a href="http://ciips.ee.uwa.edu.au/~morris/CA406/pipelines.html">The Anatomy of Modern Processors: Pipelines</a>
            </link>
            <link>
               <a href="http://granite.sru.edu/~venkatra/pipelining1.html">Pipeline Streaming</a>
            </link>
            <link>
               <a href="http://www.udayton.edu/~cps/cps560/notes/hardware/mmx/Intel/dg_chp2.htm">Pipelines of Superscalar (Pentium Family) and Dynamic Execution (P6-Family) Architectures</a>
            </link>
         </scriptElement>
         <subsubtopic name="supersk">Superskalarität</subsubtopic>
         <p>Superskalare CPUs versuchen den Durchsatz durch CPU-interne Parallelität zu erhöhen. Hierzu werden Funktionseinheiten derselben Funktionseinheiten physisch mehrfach realisiert und angeboten. Zur Versorgung der Einzeleinheiten können entweder explizite <a href="#ILP">VLIW-basierte Ansätze</a> bereits zur Übersetzungszeit oder dynamische Pipeline-basierte zur Ausführungszeit Einsatz finden.</p>
         <p>Nachfolgend wird ein Überblick der Strategien zur Ansteuerung von Funktionseinheiten in superskalaren CPUs gegeben. Gleichzeitig werden Strategien und Techniken diskutiert, die eingesetzt werden können um die Anzahl der Wartezyklen innerhalb einer Pipeline zu verringern und so ihre Auslastung zu steigern.</p>
         <ul>
            <li>
               <b>Hardwaremaßnahmen</b>
               <br/>Zur Behebung struktureller Ressourcen-Konflikte können zusätzliche Hardwarebausteine wie parallel Speicherzugriffskanäle und -controller eingesetzt werden um die zwangsweise Serialisierung der Instruktionen an diesen<gerquot>Engstellen</gerquot>(engl. <em>bottle neck</em>) zu verhindern.</li>
            <li>
               <b>Kontrollfluß-Modifikationen</b>
               <br/>Zur Erhöhung der Auslastung einer gegebenen CPU kann die Verarbeitungsreihenfolge der Instruktionen eines Programms von der Reihenfolge ihres Auftretens im Programm abweichen. Hierbei werden zwei Verarbeitungstypen unterschieden:<ul>
                  <li>
                     <em>In-order-Execution</em>
                     <br/>Hierbei wird die Reihenfolge der im Programm codierten Befehle zunächst nicht verändert, sondern durch gegeabelte Pipelines auf verschiedene Ausführungseinheiten verteilt und so parallelisiert. Bekanntestes Beispiel für diesen Ansatz ist die <a href="#pentPipe">Pipeline des Pentium</a> .</li>
                  <li>
                     <em>Out-of-Order-Execution</em>
                     <br/>Instruktionen können gleichsam<gerquot>auf Vorrat</gerquot>ausgeführt werden um den Leerlauf, der durch NOP-Operationen entstünde, produktiv zu nutzen.</li>
               </ul>
            </li>
            <li>
               <b>Registersatz-Modifikationen</b>
               <br/>Die während der Out-of-order-Ausfürhung entstehenden (noch) nicht benötigten Berechnungsergebnisse werden  -- um störende Wechselwirkungen mit den regulär verarbeiteten Instruktionen auszuschließen -- in separaten Registern (sog. <em>Schattenregistern</em>) abgelegt.</li>
            <li>
               <b>Sprungvorhersage</b>
               <br/>Um die Produktion nicht mehr benötigter Resulate möglichst auszuschließen wird durch zusätzlichen Aufwand eine Sprungvorhersage betrieben, die es ermöglicht (mit einer gewissen Wahrscheinlichkeit) das Sprungziel vorherzubestimmen und die (vermutlich) benötigten Befehle<gerquot>auf Vorrat</gerquot>in die Pipeline zu laden.</li>
            <li>
               <b>Compilermaßnahmen</b>
               <br/>Ist der verwendete Übersetzer auf die später verwendete Zielarchitektur abgestimmt, so können gewisse vorausschauende Optimierungen bereits vor der Laufzeit vorgenommen werden.</li>
         </ul>
         <p>Neben dem Einsatz superskalarer Techniken zur Steierung des Durchsatzes der CPU hat sich in jüngerer Zeit <em>simulatanes Multithreading</em> zur weiteren Leistungssteierung am Markt etabliert.</p>
         <subsubtopic name="ht">Multithreading-CPUs</subsubtopic>
         <p>Multithreading-CPUs führen die Unterstützung nebenläufig ausführbarer Programmteile noch einen Schritt weiter über die Möglichkeiten des <a href="#ILP">expliziten Parallelismus auf Instruktionsebene</a> hinaus und nehmen Anleihen bei den symmetrischen Multiprozessorsystemen, welche in einem System mehrere eigenständige CPUs vereinen.</p>
         <p>Um jedoch der Kostensituation und verschiedenen Einsatzproblemen von Multiprozessorsystemen zu begegnen bieten Multithreading-CPUs nur simultane Instruktionsverarbeitung an ohne alle Ausführungsressourcen (wie Registersätze) mehrfach zu realisieren.</p>
         <p>Grundsätzlich steuert in einer Multithreading-CPU genau ein Leitwerk mehrere getrennt ansprechbare Recheneinheiten an. Auf diese Weise können sich in einem Taktzyklus mehrere Instruktionen in der <a href="#EX">Befehlsausführungsphase</a> befinden und Ergebnisse liefern.</p>
         <p>Bei Multithreading-CPUs vergrößert sich tendenziell der Grad der Konkurrenz um die verfügbaren Ressourcen wie Register, Zwischenspeicher (Caches) und andere prozessorinterne Verwaltungseinheiten, so daß erhöhter Aufwand für die Synchronisation und Behebung der auftretenden Zugriffskonflikte anzusetzen ist.</p>
         <p>Grundsätzlich werden (nach <a href="index.html#maertin">[Mär01, S. 250]</a> mit Verweis auf          <name>Culler</name> ) drei Varianten der Multithreading-Realisierung in einer CPU unterschieden:</p>
         <ul>
            <li>
               <b>Blocked Multithreading</b>:<br/>Eine begrenzte Anzahl zusätzlicher Register wird bereitgestellt, jedoch keine zusätzlichen Verarbeitungsressourcen. Als Konsquenz muß ein rechenbereiter Thread waren, bis ihm eine freie Rechenkomponente zugeteilt wird.</li>
            <li>
               <b>Interleaved Multithreading</b>:<br/>In jedem Taktzyklus wird erneut ein Thread zur Ausfürhung ausgewählt. Ein gegebener Befehl muß auf seine Ausführung daher so lange waren, bis er zur Abarbeitung selektiert wird.</li>
            <li>
               <b>Simulataneous Multithreading</b>(SMT):<br/>Kombiniert interleaved Multithreading und superskalare Ansätze um die gleichzeitige Ausführung von Instruktionen in einem Taktzyklus ermöglichen zu können.</li>
         </ul>
         <p>
            <illustrationLink ref="ht"/> zeigt die Ausführung nebenläufiger Befehlsfolgen auf einer superskalaren, einer Multiprozessor- und einer Multithreading-CPU.<br/>Während die superskalare CPU die vorhandenen Ressourcen durch die auftretenden Wartezyklen nicht vollständig ausnutzen (48% ungenutzter Anteil im Beispiel) kann kann das Multiprozssorsystem zwar den Durchsatz des Gesamtsystems durch die parallele Ausführung separater Befehlsfolgen erhöhen bietet jedoch prozentual nur in etwa dieselbe Auslastung der vorhandenen Ressourcen.<br/>Im Idealfalle kann eine Multithreading-basierte CPU, durch geeignete Zuteilung der Berechnungsaufgaben an die vorhandenen Berechnungsressourcen einen höheren Gesamtdurchsatz der CPU erreichen.</p>
         <illustration id="ht" width="521" caption="Ausführung nebenläufiger Befehlsfolgen" gfx="sysarch/ht.png"/>
         <p>Gegenwärtig wird SMT durch Intel in seiner Pentium-4-Architektur popularisiert und für den Massenmarkt angeboten. Erste Erfahrungen mit diesem CPU-Typ stimmen durchaus positiv, wenngleich der Geschwindigkeitszugewinn sich lediglich im Bereich von 30% bewegt, was unter anderem auf die fortbestehende Konkurrenz um verschiedene Prozessor-Ressourcen zurückzuführen ist.</p>
         <scriptElement type="links" title="Weiterführende Links">
            <link>
               <a href="http://en.wikipedia.org/wiki/Hyper-threading">Hyperthreading</a>
            </link>
            <link>
               <a href="http://english.aopen.com.tw/tech/techinside/HyperThreading.htm">Hyper-Threading Technology</a>
            </link>
            <link>
               <a href="http://www.intel.com/technology/hyperthread/">Hyperthreading @ Intel</a>
            </link>
            <link>
               <a href="http://www.hardwareanalysis.com/content/article/1557.2/">SMT vs. SMP</a>
            </link>
         </scriptElement>
         <subtopic name="parallelverarbeitung">Parallelverarbeitung</subtopic>
         <subsubtopic name="parTyp">Rechnerklassifikation</subsubtopic>
         <p>Aspekte der Parallelverarbeitung werden in aktuellen Rechnerarchitekturen auf verschiedenste Weise und unterschiedlichen Ebenen genutzt, so daß eine trennscharfe Unterscheidung für gegenwärtige Prozessoren kaum mehr möglich ist, da auch diese bereits Parallelitätstechniken einsetzen.</p>
         <p>Klassischerweise werden nach           <name>Flynn</name>  die vier in  <illustrationLink ref="FlynnSchema"/>  dargestellten Verarbeitungsformen unterschieden, die jedoch heute nicht mehr in ihrer ursprünglichen Reinform auftreten:</p>
         <ul>
            <li>
               <b>
                  <keyword>SISD-Rechner</keyword>
               </b>:<br/>
        In diese Klasse fallen die mit genau einem Leiterwerk und einem Rechenwerk ausgestatteten klassischen Universalrechner.<br/>
        SISD-Rechner führen zu einem gegebenen Zeitpunkt daher genau einen Befehl auf einem verarbeiteten Datum aus.<br/>
        Die gegebene Klassifikation läßt jedoch überlappende Ausführung, wie sie beispielsweise durch  <a href="#pipelineing">Phasen-Piplelines</a>  entstehen ebenso außer Acht, wie Parallelität auf Ebene der Rechenwerke wie sie durch  <a href="#ht">Multithreading-CPUs</a>  eingeführt wird.</li>
            <li>
               <b>
                  <keyword>SIMD-Rechner</keyword>
               </b>:<br/>
        In diese Klasse fallen alle mit genau einem Leitwerk und mehreren Rechenwerken ausgestatteten <keyword>Feldrechner</keyword> oder <keyword>Array-Prozessoren</keyword>.<br/>
        Durch die Duplizität der Rechenwerke gestatten SIMD-Rechner die parallele Ausführung jeder Einzelinstruktion auf verschiedenen Eingangsdaten zu einem Zeitpunkt. Jedoch muß auf allen verarbeiteten Daten jeweils dieselbe Instruktion zur Ausführung gebracht werden.<br/>
        Typische Anwendungsfelder dieses Rechnertyps umfassen die Verarbeitung multimedialer Bild- und Tondaten.<br/>
        Auch <keyword>Vektorprozessoren</keyword>, die Operanden, welche aus einer festen Anzahl von Skalarwerten bestehen, verarbeiten können gemäß           <name>Giloi</name>  der Klasse der SIMD-Rechner zugeordnet werden.</li>
            <li>
               <b>MISD-Rechner</b>:<br/>
        Dieser Rechnertypus -- der mehrere Leitweitwerke, aber nur ein Rechenwerk vorsehen würde -- ist in der Praxis bisher nicht anzutreffen. Eine mögliche Realisierung dieser Rechnerklasse müßte ein <gerquot>fließbandartig</gerquot> betriebenes Rechenwerk mit Daten, die durch unterschiedliche Leitwerke bereitgestellt werden, beschicken.</li>
            <li>
               <b>MIMD-Rechner</b>:<br/>
        In diese Klasse fallen alle Rechner, welche über mehrere Leit- und mehrere unabhängige Rechenwerke verfügen.<br/>
        Diesem Rechnertypus sind alle Formen von Parallelrechnern mit mehreren eigenständigen CPUs sowie verschaltete Rechner zuzuordnen, sofern sich diese als genau ein virtuelles System präsentieren.</li>
         </ul>
         <illustration id="FlynnSchema" width="420" caption="Rechnerklassifikation nach Flynn" gfx="sysarch/FlynnSchema.png"/>
         <p>Das           <name>Flynn</name> sche Schema stößt bereits bei der Rubrizierung aktuell verfügbarer Prozessoren, wie den mit mehreren separaten Funktionseinheiten ausgestatteten Intel- oder AMD-CPUs an seine Grenzen. Zwar kann jede einzelne Funktionseinheit der Klasse SIMD zugeordnet werden, jedoch ist eine eindeutige Klassifikation der Gesamt-CPU nicht mehr unstrittig möglich.</p>
         <subsubtopic name="parMem">Speichergekoppelte-Umgebungen</subsubtopic>
         <p>In speichergekoppelten Umgebungen steht allen physischen Prozessoren ein gemeinsamer Hauptspeicher zur Verfügung. Anhand der physischen Realisierung dieses Speichers wird zwischen Architekturen des Typs <em>
               <keyword>Unified Memory Access</keyword>
            </em> (<keyword>UMA</keyword>) und <em>
               <a href="http://en.wikipedia.org/wiki/NUMA">
                  <keyword>Non-Unified Memory Access</keyword>
               </a>
            </em> (<keyword>NUMA</keyword>) unterschieden.</p>
         <p>Die <keyword>enge Kopplung</keyword> zwischen den Einzelprozessoren der UMA-Realisierungen setzt voraus, daß alle Prozessoren durch leistungsfähige Busse Zugang zum gemeinsam genutzten Speicher erhalten. Daher ist der physische Abstand zwischen jedem Einzelprozessor und dem Hauptspeicher in der Regel identisch groß.<br/>
            Aufgrund der sich daraus inhärent ergebenden Sternarchitektur wird dieser Parallrechnertyp auch als <a href="http://en.wikipedia.org/wiki/SMP">
               <em>
                  <keyword>Symmetrisches Multiprocessing</keyword>
               </em>
            </a> bezeichnet.</p>
         <p>Dieser Rechnertyp ist in der Praxis -- mit Ausbaustufen von bis zu acht verschalteten Prozessoren -- häufig anzutreffen. Die Integration größerer CPU-Anzahlen sind in Ihrer Realisierung als problematisch anzusehen, da die Konkurrenz um den Hauptspeicher bei steigender CPU-Anzahl zu überproportionalen Leistungseinbußen führt. Zusätzlich kann der Zugewinn an Busbandbreite nicht mit der Leistungssteigerung der CPUs Schritt halten, weshalb sich jeder Speicherzugriff als Performance aufzehrende Engstelle erweist.</p>
         <p>Durch <keyword>lose Kopplung</keyword> in NUMA-Umgebungen, welche inhärent die unterschiedliche Realisierung der Speicherzugriffe für alle angebundenen CPUs zulassen können diese Engpässe vermieden werden. Hierzu kann an jedem physischen Konten eigener Hauptspeicher angesiedelt werden. Die einzelnen <gerquot>Hauptspeicherinseln</gerquot> werden durch zusätzliche Hardware oder das das verwaltetende Betriebssystem zu einem virtuellen Gesamtspeicher verschaltet.</p>
         <subsubtopic name="parMsg">Nachrichtengekoppelte-Umgebungen</subsubtopic>
         <p>Wird die Forderung nach gemeinsamem Speicher zwischen den Einzelknoten aufgegeben, so lassen sich flexiblere Umsetzungen finden, die auch deutlich höhere CPU-Anzahlen umfassen können.<br/>
            Jedoch entfällt dann der gemeinsame Speicher als Medium des Datenaustausches zwischen den Einzelprozessoren und muß durch eine explizite Kommunikationinfrastruktur ersetzt werden.</p>
         <p>Hierbei kommen typischerweise Ansätze der Botschaftenvermittlung (<em>message passing</em>) zum Einsatz, welche Datenpakete zwischen den beteiligten Prozessorknoten versenden.</p>
         <p>Eine bekannte Umsetzung in diesem Umfeld stellt das <a href="http://en.wikipedia.org/wiki/Message_Passing_Interface">
               <em>Message Passing Interface</em>
            </a> dar, welches eine Programmiersprachen-Bibliothek zur Verfügung stellt, welche die schnelle Botschaftenvermittlung zwischen verteilt ausgeführten Fortran- oder C-basierten Applikationen ermöglicht.</p>
         <subsubtopic name="parPerf">Leistungsabschätzung</subsubtopic>
         <p>Die zu erwartende Leistungssteigerung (<em>
               <keyword>speedup</keyword>
            </em>) eines Multiprozessorsystems kann durch verschiedene Gesetze abgeschätzt werden. Bekanntester Ansatz hierzu ist das <a href="http://en.wikipedia.org/wiki/Amdahl%27s_law">
               <name>Amdahl</name>sche Gesetz</a>.</p>
         <p>In seiner in <illustrationLink ref="amdahl"/> abgebildeten Form setzt die parallel (<code>p<sub>parallel</sub>
            </code>) und seriell (<code>p<sub>seriell</sub>
            </code>) auszuführenden Programmteile, sowie die Anzahl der verfügbaren CPUs (<code>n<sub>CPU</sub>
            </code>) für eine feste Problemgröße in Beziehung und ermittelt daraus statisch die zu erwartetende Leistungssteigerung (<code>S</code>).<br/>
        Für den Zusammehang zwischem seriell und parallel ausführbarem Code gilt dabei: <code>p<sub>seriell</sub> + p<sub>parallel</sub> = 1</code>.</p>
         <illustration id="amdahl" width="303" caption="Amdahlsches Gesetz" gfx="sysarch/amdahl.png"/>
         <p>
            <illustrationLink ref="amdahlVerlauf"/> zeigt den abgeschätzen Geschwindigkeitsgewinn relativ zu den betrachteten Frieheitsgraden.</p>
         <illustration id="amdahlVerlauf" width="600" caption="Abschätzung des Speedups nach Amdahl" gfx="sysarch/amdahlVerlauf.png"/>
         <subtopic name="fallstudie">Fallstudie: Die virtuelle Rechnerarchitektur der Java-Maschine</subtopic>
         <div xml:base="file:/I:/development/vorlesung/sharedScriptParts/JVM/jvm.xml">
            <p>Kern der oft apostrophierten <a href="http://www.jeckle.de/vorlesung/java/script.html#interpretierbar">Plattformunabhängigkeit</a> der Programmiersprache Java ist die Generierung eines generischen Zwischenformates -- des Byte-Codes. Dieser wird von einer plattformabhängig implementierten Programmeinheit, der <em>Java Virtual Machine</em> (Abk. JVM) interpretativ zur Ausführung gebracht.<br/>
Jede Java-Applikation wird auf einer eigenen virtuellen Maschine zur Ausführung gebracht. Dies garantiert eine größtmögliche Abschottung, mit dem Ziel maximierter Sicherheit, der möglicherweise gleichzeitig auf einer realen Maschine ausgeführten Java-Programme voneinander.<br/>
Das Konzept der virtuellen Maschine, die als Programm auf einer realen Hardware abläuft, ermöglicht eine vergleichsweise einfache und schnelle Portierbarkeit auf neue Zielumgebungen, da lediglich die virtuelle Maschine an die veränderte reale Maschine angepaßt werden muß.</p>
            <p>Der Gedanke virtueller Maschinen, die generischen Zwischencode -- oftmals auch als <em>P-Code</em> bezeichnet -- ausführen, ist nicht neu. Bereits USCD Pascal, E-BASIC und die verschiedenen SmallTalk-Implementierungen, setzt diesen praktisch um.<br/>
Die Realisierung der Befehlsfolgen (Opcodes) innerhalb der virtuellen Maschine von Java ähnelt teilweise frappant der Architektur der für die Züricher Pascal-Implementierung entwickelten (abstrakten) P-Maschine.</p>
            <p>Inzwischen steht mit der <a href="http://www-1.ibm.com/servers/eserver/zseries/zaap/">zAAP</a> (zSeries Application Assist Processor)-Hardware für die IBM-Mainframemaschinen <em>z890</em> und <em>z990</em> sogar eine vollständige Hardwareimplementierung der JVM zur Verfügung, welche den Charakter der <em>virtuellen</em> zu einer <em>realen</em> Maschine weiterentwickelt.</p>
            <p>Ein Beispiel einer vollständig als Softwar realisierten <gerquot>klassischen</gerquot> virtuellen Maschine ist <a href="http://www.jeckle.de/vorlesung/java/script.html#javaInterpreter">
                  <code>java</code>
               </a>, die Bestandteil des Java-Development Toolkits von SUN ist.<br/>
Bekannte andere virtuelle Maschinen sind: <a href="http://www.kaffe.org">Kaffe</a> oder auch <a href="http://oss.software.ibm.com/developerworks/oss/jikesrvm/?origin=jikes">IBMs <em>Jikes</em>-Implementierung</a>
               <br/>
               <a href="http://www.jeckle.de/vorlesung/java/script.html#javaInterpreter">Wie bereits bekannt</a> wird eine Java-Applikation durch den Aufruf <code>java</code>, gefolgt vom Namen der Startklasse und etwaiger Kommandozeilenparameter ausgeführt. Technisch gesehen bewirkt der Aufruf zunächt die Erzeugung einer neuen Instanz der virtuellen Maschine, auf welcher die Programm-Abarbeitbung mit der <a href="http://www.jeckle.de/vorlesung/java/script.html#mainMethode">
                  <code>main</code>-Methode</a> der Startklasse begonnen wird.<br/>
Eine Instanz einer virtuellen Maschine existiert, solange Programmfäden (engl. <em>Threads</em>) (genaugenommen: non-deamon Threads) ausgeführt werden, bzw. die virtuelle Maschine explizit beendet wird (mit dem API-Aufruf <a fixedType="JDKcurrent" offset="java/lang/System.html#exit(int)">
                  <code>System.exit()</code>
               </a>) oder ein Fehler auftritt.</p>
            <graphic src="sharedScriptParts/jvm.gif" caption="Architektur der virtuellen Maschine (nach: Venners, B.: Inside the Java 2 Virtual Machine, chap. 5)"/>
            <p>Die wesentlichen Bestandteile der JVM sind:</p>
            <ul>
               <li>
                  <em>method area</em>
                  <br/>
   Einmal vorhanden je virtueller Maschine, wird gemeinsam von allen Threads benutzt; enthält klassenspezifische Daten (Typinformation).</li>
               <li>
                  <em>heap</em>
                  <br/>
   Einmal vorhanden je virtueller Maschine, wird gemeinsam von allen Threads benutzt; enthält die dynamisch erzeugten Objekte.</li>
               <li>
                  <em>Java VM stacks</em>
                  <br/>
   Threadspezifisch. Enthält Zustand von nicht-nativen Methodenaufrufen, deren lokale Variablen, Übergabeparameter, den möglichen Rückgabewert sowie Methoden-interne Berechnungsergebnisse. (<a fixedType="JavaJVM" offset="Overview.doc.html#6654">vgl. JVM-Spezifikation</a>)</li>
               <li>
                  <em>pc registers</em>
                  <br/>
   Threadspezifisch; enthält für jeden Zeitpunkt der Ausführung einer nicht-nativen Methode die Adresse der derzeit ausgeführten Instruktion. (<a fixedType="JavaJVM" offset="Overview.doc.html#6648">vgl. JVM-Spezifikation</a>). Während der Abarbeitung nativer Methoden ist der Wert auf <code>undefined</code> gesetzt. Konkrete Größe des virtuellen pc-Registers hängt von der Adresslänge der realen Plattform ab.</li>
               <li>
                  <em>native method stack</em>
                  <br/>
   Implementierungsspezifischer Speicherbereich zur Behandlung von nativen Methodenaufrufen. </li>
               <li>
                  <em>
                     <a name="runtimeConstantPool">runtime constant pool</a>
                  </em>
                  <br/>
   Klassen- oder Schnittstellenspezifisch. Enthält verschiedene Konstanten, die zur Übersetzungszeit feststehen und in der <code>constant_pool</code> Tabelle der class-Datei abgelegt sind. Die Funktion dieses Bereichs ähnelt dem einer konventionellen Symboltabelle. (<a fixedType="JavaJVM" offset="Overview.doc.html#22972">vgl. JVM-Spezifikation</a>)</li>
            </ul>
            <p>Die Java-Stacks sind in <em>stack frames</em> organisert. Jedem Methodenaufruf ist ein <a fixedType="JavaJVM" offset="Overview.doc.html#17257">Stack-Frame</a> zugeordnet, der beim Aufruf erzeugt (<code>push</code>), und beim Verlassen (<code>pop</code>) vom Stack entnommen wird.<br/>
Innerhalb eines Frames befindet sich</p>
            <ul>
               <li>Array der lokalen Variablen</li>
               <li>Operanden-Stack<br/>
                  <small>Wichtigste Datenstruktur innerhalb der virtuellen Maschine. Der Operanden-Stack enthält alle Eingangs- und Ausgangsdaten der verschiedenen Berechnungen. Seine Einträge sind typisierten in 32-Bit Worten organisiert; die korrekte Typisierung der Eingangoperanden wird von jedem Opcode geprüft.</small>
               </li>
               <li>Referenz auf runtime constant pool</li>
               <li>implementierungsspezifische- und debugging-Information</li>
            </ul>
            <p>Den für den Anwendungsentwickler offensichtlichsten Bestandteil der virtuellen Maschine, bilden jedoch die JVM-Instruktionen -- die Maschinensprache der JVM.<br/>
Der <a fixedType="JavaJVM" offset="Instructions.doc.html">Befehlssatz der JVM</a> umfaßt ausschließlich genau ein Byte lange Opcodes.<br/>
Die JVM ist generell <em>stack-orientiert</em>. Dies bedeutet, daß Quell- und Zieloperanden der meisten Operationen werden vom Stack entnommen, und das Ergebnis dort abgelegt. Insbesondere existieren, abgesehen von vier Verwaltungsspeicherplätzen je Ausführungs-Thread, keine virtuellen Prozessorregister, um die Implementierungsanforderungen an die reale Plattform zu minimieren.</p>
            <p>Als threadlokale Register stehen zur Verfügung:</p>
            <ul>
               <li>
                  <a fixedType="JavaJVM" offset="Overview.doc.html#6648">
                     <code>pc</code> -- program counter</a>
                  <br/>
   Enthält die Adresse der gerade ausgeführten Instruktion.<br/>
   Handelt es sich um eine native-Methode, die in einer anderen Programmiersprache ausgeführt wird, so ist der Wert <em>undefined</em>.</li>
               <li>
                  <code>optop</code>
                  <br/>
   Verweist auf die Spitze des <a fixedType="JavaJVM" offset="Overview.doc.html#28851">Operanden Stacks</a>.</li>
               <li>
                  <a fixedType="JavaJVM" offset="Overview.doc.html#17257">
                     <code>frame</code>
                  </a>
                  <br/>
   Verweist auf die Ausführungsumgebung der derzeit aktiven Methode.</li>
               <li>
                  <code>vars</code>
                  <br/>
   Ein Zeiger auf die erste lokale Variable der aktuellen Methode.</li>
            </ul>
            <p>Die Adresslänge innerhalb der JVM ist auf vier Byte (32 Bit) fixiert. Hieraus ergibt sich ein (theoretischer) Adressraum von 4 GB.<br/>
Die initiale und maximale Ausdehnung des Heaps kann durch die Kommandozeilenschalter <code>Xms</code> bzw. <code>Xmx</code> gesteuert werden (Beispiel: <code>java -Xms350M -Xmx500M HelloWorld</code> führt ein einfaches <a href="http://www.jeckle.de/vorlesung/java/script.html#buildcycle">Hello-World-Beispiel</a> mit einer anfänglichen Speicherausstattung von 350 MB aus, die im Verlaufe des Programmablaufs auf höchstens 500 MB anwachsen kann.)</p>
            <p>Das <b>
                  <a name="JVMTypsystem">Typsystem der JVM</a>
               </b> lehnt sich eng an das der Hochsprache an. <small>(<a href="http://www.jeckle.de/vorlesung/java/script.html#typsystem">Zur Erinnerung: primitive Typen in Java)</a>
               </small>
               <br/>
Zusätzlich erweitert es die Primitivtypen um einen Adresstypen <code>returnAddress</code> und führt explizite Referenztypen auf die verschiedenen high-level Typen (Klassen, Schnittstellen, Arrays) ein.</p>
            <graphic src="java/jvmTypsystem.gif" caption="Typsystem der virtuellen Maschine"/>
            <p>Datentypen der JVM:</p>
            <ul>
               <li>
                  <code>byte</code>
                  <br/>
   Vorzeichenbehaftete 8-Bit Zahl in Zweierkomplementdarstellung.</li>
               <li>
                  <code>short</code>
                  <br/>
   Vorzeichenbehaftete 16-Bit Zahl in Zweierkomplementdarstellung.</li>
               <li>
                  <code>int</code>
                  <br/>
   Vorzeichenbehaftete 32-Bit Zahl in Zweierkomplementdarstellung.</li>
               <li>
                  <code>long</code>
                  <br/>
   Vorzeichenbehaftete 64-Bit Zahl in Zweierkomplementdarstellung.</li>
               <li>
                  <code>char</code>
                  <br/>
   Vorzeichenbehaftete 16-Bit Zahl zur Darstellung von Unicode-Zeichen.</li>
               <li>
                  <code>float</code>
                  <br/>
   32-Bit Binärdarstellung einer Fließkommazahl gemäß <a href="http://standards.ieee.org/reading/ieee/std_public/description/busarch/754-1985_desc.html">IEEE 754-1985</a>.</li>
               <li>
                  <code>double</code>
                  <br/>
   64-Bit Binärdarstellung einer Fließkommazahl gemäß <a href="http://standards.ieee.org/reading/ieee/std_public/description/busarch/754-1985_desc.html">IEEE 754-1985</a>.</li>
               <li>
                  <code>boolean</code>
                  <br/>
   Wird zwar durch die JVM definiert, jedoch existieren keine Opcodes, die Parameter dieses Typs erwarten. Der Compiler setzt Anweisungen die <code>boolean</code>-Typen enthalten als Operationen auf <code>int</code>-Typen um.</li>
               <li>
                  <code>returnAddress</code>
                  <br/>
   Für den Programmierer nicht zugänglicher Typ, der Sprungadressen aufnimmt.</li>
               <li>Referenztypen<br/>
   Verweisen auf Klassen, Arrays oder Schnittstellen.<br/>
   Der Wert kann auch <code>null</code> sein, wobei die JVM keine konkrete Darstellung dieses Wertes unterstellt.</li>
            </ul>
            <p>
               <a name="VMInstruktionen">Jede Bytecode-Instruktion</a> besteht zunächst aus ihrem Opcode, optional gefolgt von den benötigten Operanden. Diese stehen jedoch nicht für sich, sondern sind eingebettet in den organisatorischen Rahmen der <code>class</code>-Datei, deren <a href="#classFileFormat">Format</a> im Anschluß vorgestellt wird.</p>
            <p>Die verschiedenen Maschineninstruktionen lassen sich in Klassen einteilen:</p>
            <p>
               <b>Instruktionen zum Zugriff auf lokale Variablen</b>:</p>
            <tabular>
               <head length="2">
                  <column title="Instruktion"/>
                  <column title="Funktion"/>
               </head>
               <body>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc12.html#ret">
                           <code>ret</code>
                        </a>
                     </cell>
                     <cell>Rücksprung aus Subroutine, wird in der Implementierung von <a href="#finally">
                           <code>finally</code>
                        </a> benutzt</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc.html#aload">
                           <code>aload</code>
                        </a>
                     </cell>
                     <cell>Lädt Referenz von spezifisch indizierter Position auf den Operanden-Stack</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc.html#aload_n">
                           <code>aload_<em>&lt;n&gt;</em>
                           </code>
                        </a>
                     </cell>
                     <cell>Lädt Referenz auf Operanden-Stack (Index im Opcode explizit angegeben)</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc.html#astore">
                           <code>astore</code>
                        </a>
                     </cell>
                     <cell>Speichert auf Operanden Stack liegenden Wert in lokale Variable</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc.html#astore_n">
                           <code>astore_<em>&lt;n&gt;</em>
                           </code>
                        </a>
                     </cell>
                     <cell>Legt Referenz in lokaler Variable auf Operanden-Stack ab (Index wird im Opcode explizit angegeben)</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dload">
                           <code>dload</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>double</code>-Wert aus lokaler Variable auf den Operanden-Stack</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dstore">
                           <code>dstore</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>double</code>-Wert vom Operanden-Stack und legt ihn in lokaler Variable ab</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#fload">
                           <code>fload</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>float</code>-Wert aus lokaler Variable auf den Operanden-Stack</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#fstore">
                           <code>fstore</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>float</code>-Wert vom Operanden-Stack und legt ihn in lokaler Variable ab</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#iload">
                           <code>iload</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>int</code> auf Operanden-Stack (Index im Opcode explizit angegeben)</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#iload_n">
                           <code>iload_<em>&lt;n&gt;</em>
                           </code>
                        </a>
                     </cell>
                     <cell>Lädt <code>int</code>-Wert aus lokaler Variable auf den Operanden-Stack</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#istore">
                           <code>istore</code>
                        </a>
                     </cell>
                     <cell>Legt <code>int</code>-Wert von spezifisch indizierter Position in lokaler Variable auf Operanden-Stack ab</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#istore_n">
                           <code>istore_<em>&lt;n&gt;</em>
                           </code>
                        </a>
                     </cell>
                     <cell>Lädt <code>int</code>-Wert vom Operanden-Stack und legt ihn in lokaler Variable ab</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lload">
                           <code>lload</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>long</code>-Wert aus lokaler Variable auf den Operanden-Stack</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lstore">
                           <code>lstore</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>long</code>-Wert vom Operanden-Stack und legt ihn in lokaler Variable ab</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#iinc">
                           <code>iinc</code>
                        </a>
                     </cell>
                     <cell>Inkrementiert lokale Variable um fixe <code>int</code>-Zahl</cell>
                  </row>
               </body>
            </tabular>
            <p>
               <b>Instruktionen zur expliziten Modifikation des Operanden-Stacks</b>:</p>
            <tabular>
               <head length="2">
                  <column title="Instruktion"/>
                  <column title="Funktion"/>
               </head>
               <body>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc1.html#bipush">
                           <code>bipush</code>
                        </a>
                     </cell>
                     <cell>Ablegen eines <a href="#primitiveTypeByte">
                           <code>byte</code>-Wertes</a> auf dem Operanden-Stack</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#sipush">
                           <code>sipush</code>
                        </a>
                     </cell>
                     <cell>Ablegen eines <a href="#primitiveTypeShort">
                           <code>short</code>-Wertes</a> auf dem Operanden-Stack</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc11.html#pop">
                           <code>pop</code>
                        </a>
                     </cell>
                     <cell>Entnimmt und verwirft (de facto: löscht) obersten Operanden-Stack-Eintrag.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc11.html#pop2">
                           <code>pop2</code>
                        </a>
                     </cell>
                     <cell>Entnimmt (de facto: löscht) obersten beiden Operanden-Stack-Einträge.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc13.html#swap">
                           <code>swap</code>
                        </a>
                     </cell>
                     <cell>Tauscht die beiden obersten Operanden-Stack-Einträge aus.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#ldc">
                           <code>ldc</code>
                        </a>
                     </cell>
                     <cell>Ablegen eines Elements (referenziert über 16-Bit Index) des <a href="#runtimeConstantPool">runtime constant pools</a> auf dem Operanden-Stack</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#ldc_w">
                           <code>ldc_w</code>
                        </a>
                     </cell>
                     <cell>Ablegen eines Elements (referenziert über 32-Bit Index) des <a href="#runtimeConstantPool">runtime constant pools</a> auf dem Operanden-Stack</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc.html#aconst_null">
                           <code>aconst_null</code>
                        </a>
                     </cell>
                     <cell>Legt <code>null</code> auf dem Operanden-Stack ab.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dconst_d">
                           <code>dconst_<em>&lt;d&gt;</em>
                           </code>
                        </a>
                     </cell>
                     <cell>Legt <code>double</code> Konstante auf dem Operanden-Stack ab.<br/>
                        <code>dconst_0</code> die Konstante <code>0.0</code>, bzw. <code>dconst_1</code> den Wert <code>1.0</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#fconst_f">
                           <code>fconst_<em>&lt;f&gt;</em>
                           </code>
                        </a>
                     </cell>
                     <cell>Legt <code>float</code> Konstante auf dem Operanden-Stack ab.<br/>
                        <code>fconst_0</code> die Konstante <code>0.0</code>, bzw. <code>fconst_1</code> den Wert <code>1.0</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#iconst_i">
                           <code>iconst_<em>&lt;i&gt;</em>
                           </code>
                        </a>
                     </cell>
                     <cell>Legt <code>int</code>-Konstante auf dem Operanden-Stack ab.<br/>
         Es existieren Opcodes für folgende Konstanten: <code>iconst_m1</code> -- -1; <code>iconst_0</code> -- 0; <code>iconst_1</code> -- 1; <code>iconst_2</code> -- 2; <code>iconst_3</code> -- 3; <code>iconst_4</code> -- 4; <code>iconst_5</code> --5.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dup">
                           <code>dup</code>
                        </a>
                     </cell>
                     <cell>Dupliziert oberstes Element des Operanden-Stacks.<br/>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dup_x1">
                           <code>dup_x1</code>
                        </a> legt das neue Element als zweitunterstes auf dem Stack ab.<br/>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dup_x2">
                           <code>dup_x2</code>
                        </a> legt das neue Element, abhängig vom Stack-Inhalt, als zweit- oder drittunterstes auf dem Stack ab.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dup2">
                           <code>dup2</code>
                        </a>
                     </cell>
                     <cell>Dupliziert die beiden obersten Elemente des Operanden-Stacks.<br/>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dup2_x1">
                           <code>dup2_x1</code>
                        </a> legt die neuen Elemente als zweitunterstes und folgendes auf dem Stack ab.<br/>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dup2_x2">
                           <code>dup2_x2</code>
                        </a> legt die neuen Elemente, abhängig vom Stack-Inhalt, als zweit- oder drittunterstes und folgendes auf dem Stack ab.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lconst_l">
                           <code>lconst_<em>&lt;l&gt;</em>
                           </code>
                        </a>
                     </cell>
                     <cell>Legt <code>long</code> Konstante auf dem Operanden-Stack ab.<br/>
         Es existieren Opcodes für folgende Konstanten: <code>iconst_0</code> -- 0; <code>iconst_1</code> -- 1.</cell>
                  </row>
               </body>
            </tabular>
            <p>
               <b>Instruktion zur Steuerung des Kontrollflußes</b>:</p>
            <tabular>
               <head length="2">
                  <column title="Instruktion"/>
                  <column title="Funktion"/>
               </head>
               <body>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc5.html#goto">
                           <code>goto</code>
                        </a>
                     </cell>
                     <cell>Bedingungsloser Sprung innerhalb derselben Methode. <small>Der anzugebende <em>branch offset</em> ist auf 16-Bit fixiert, woraus sich ableiten läßt, daß das Opcodesegment einer Methode niemals (in der JVM-Version 1.3) die Größe von 64KByte überschreiten darf. Näheres zu den Einschränkungen der virtuellen Maschine findet sich in im <a fixedType="JavaJVM" offset="ClassFile.doc.html#88659">Abschnitt 4.10 der JVM-Spezifikation</a>, sowie in der <a href="#classFileFormat">Diskussion des Class-File Formats</a>
                        </small>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc5.html#goto_w">
                           <code>goto_w</code>
                        </a>
                     </cell>
                     <cell>Bedingungsloser Sprung innerhalb derselben Methode (mit 32-Bit Offset)</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#if_acmpcond">
                           <code>if_acmp<em>&lt;cond&gt;</em>
                           </code>
                        </a>
                     </cell>
                     <cell>Bedingter Sprung im Falle der Gültigkeit der Bedingung.<br/>
         Die zu vergleichenden Operanden werden als Referenzen übergeben. Als Bedingungen stehen Gleichheit (<code>eq</code>) und Ungleichheit (<code>ne</code>) zur Verfügung.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#if_icmpcond">
                           <code>if_icmp<em>&lt;cond&gt;</em>
                           </code>
                        </a>
                     </cell>
                     <cell>Bedingter Sprung im Falle der Gültigkeit der Bedingung.<br/>
         Die zu vergleichenden Operanden werden als <code>int</code>-Werte übergeben. Als Bedinungen stehen zur Verfügung: Gleichheit (<code>eq</code>), Ungleichheit (<code>ne</code>), Kleiner (<code>lt</code>), Kleiner oder Gleich (<code>le</code>), Größer (<code>gt</code>) und Größer oder Gleich (<code>ge</code>).</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#ifcond">
                           <code>if<em>&lt;cond&gt;</em>
                           </code>
                        </a>
                     </cell>
                     <cell>Bedingter Sprung, nach Vergleich des obersten Elements des Operanden-Stacks mit Null<br/>
         Für spezifische Vergleiche stehen folgende Opcodes zur Verfügung: Geleichheit (<code>ifeq</code>), Ungleichheit (<code>ifne</code>), Kleiner (<code>iflt</code>), Kleiner oder Gleich (<code>ifle</code>), Größer (<code>ifgt</code>), Größer oder Gleich (<code>ifge</code>).</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#ifnonnull">
                           <code>ifnonnull</code>
                        </a>
                     </cell>
                     <cell>Bedingter Sprung -- im Falle der Ungleichheit -- nach Vergleich der auf dem Operanden-Stack befindlichen Referenz mit Null</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#ifnull">
                           <code>ifnull</code>
                        </a>
                     </cell>
                     <cell>Bedingter Sprung -- im Falle der Gleichheit -- nach Vergleich der auf dem Operanden-Stack befindlichen Referenz mit Null</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc7.html#jsr">
                           <code>jsr</code>
                        </a>
                     </cell>
                     <cell>Unbedingter Sprung, unter Sicherung der Rücksprungadresse auf dem Operanden-Stack, zu 16-Bit Adresse.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc7.html#jsr_w">
                           <code>jsr_w</code>
                        </a>
                     </cell>
                     <cell>Unbedingter Sprung, unter Sicherung der Rücksprungadresse auf dem Operanden-Stack, zu 32-Bit Adresse.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lookupswitch">
                           <code>lookupswitch</code>
                        </a>
                     </cell>
                     <cell>Zugriff auf Sprungtabelle per Schlüssel und anschließende Verzweigung.<br/>
         Benutzt zur Implementierung des <a href="#switchStatement">
                           <code>switch</code>
                        </a>-Konstrukts</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc14.html#tableswitch">
                           <code>tableswitch</code>
                        </a>
                     </cell>
                     <cell>Indexbasierter Zugriff auf Sprungtabelle und anschließende Verzweigung.</cell>
                  </row>
               </body>
            </tabular>
            <p>
               <b>Instruktionen zur Operation auf Klassen und Objekten</b>:</p>
            <tabular>
               <head length="2">
                  <column title="Instruktion"/>
                  <column title="Funktion"/>
               </head>
               <body>
                  <row>
                     <cell>
                        <a name="anewarray" fixedType="JavaJVM" offset="Instructions2.doc.html#anewarray">
                           <code>anewarray</code>
                        </a>
                     </cell>
                     <cell>Array-Erzeugung an definierter Stelle im <a href="#runtimeConstantPool">Laufzeit-Konstanten-Pool</a>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a name="checkcast" fixedType="JavaJVM" offset="Instructions2.doc2.html#checkcast">
                           <code>checkcast</code>
                        </a>
                     </cell>
                     <cell>Typkompatibilitätsprüfung (<a href="#OpcodeException">siehe Beispiel</a>)</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#instanceof">
                           <code>instanceof</code>
                        </a>
                     </cell>
                     <cell>Prüft ob Objekt gegebenen Typ hat (d.h. Ausprägung der Klasse -- oder einer Subklasse -- ist; das Interface implementiert; Array-Kompatibel ist)</cell>
                  </row>
                  <row>
                     <cell>
                        <a name="new" fixedType="JavaJVM" offset="Instructions2.doc10.html#new">
                           <code>new</code>
                        </a>
                     </cell>
                     <cell>Erzeugt neues Objekt<br/>
                        <small>
                           <em>Hinweis</em>: Die Punktnotation zur Trennung der Pakethierarchien wird hier durch Slash <gerquot>/</gerquot> ersetzt.</small>
                     </cell>
                  </row>
               </body>
            </tabular>
            <p>
               <b>Instruktionen zur Methodenausführung</b>:</p>
            <tabular>
               <head length="2">
                  <column title="Instruktion"/>
                  <column title="Funktion"/>
               </head>
               <body>
                  <row>
                     <cell>
                        <a name="invokespecial" fixedType="JavaJVM" offset="Instructions2.doc6.html#invokespecial">
                           <code>invokespecial</code>
                        </a>
                     </cell>
                     <cell>Ruft <a href="#2.4.4">Instanzenmethode</a> auf; mit besonderer Behandlung bestimmter Umstände.<br/>
                        <small>
                           <em>Hinweis</em>: Diese Instruktion wurde umbenannt, frühere JDK-Versionen benutzen <code>invokeonvirtual</code>.</small>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#invokestatic">
                           <code>invokestatic</code>
                        </a>
                     </cell>
                     <cell>Ruft statische <a href="#klassenmethode">Klassenmethode</a> auf.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#invokevirtual">
                           <code>invokevirtual</code>
                        </a>
                     </cell>
                     <cell>Ruft Instanzenmethode auf.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#invokeinterface">
                           <code>invokeinterface</code>
                        </a>
                     </cell>
                     <cell>Ruft Schnittstellenmethode auf.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc.html#areturn">
                           <code>areturn</code>
                        </a>
                     </cell>
                     <cell>Retourniert Referenz auf Speicherobjekt nach Methodenausführung.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dreturn">
                           <code>dreturn</code>
                        </a>
                     </cell>
                     <cell>Retourniert <code>double</code>-Wert nach Methodenausführung.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#freturn">
                           <code>freturn</code>
                        </a>
                     </cell>
                     <cell>Retourniert <code>float</code>-Wert nach Methodenausführung.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#ireturn">
                           <code>ireturn</code>
                        </a>
                     </cell>
                     <cell>Retourniert <code>int</code>-Wert nach Methodenausführung.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lreturn">
                           <code>lreturn</code>
                        </a>
                     </cell>
                     <cell>Retourniert <code>long</code>-Wert nach Methodenausführung.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc12.html#return">
                           <code>return</code>
                        </a>
                     </cell>
                     <cell>Retourniert nach Methodenausführung ohne Rückgabewert (<code>void</code>-Methode).</cell>
                  </row>
               </body>
            </tabular>
            <p>
               <b>Instruktionen zum Zugriff auf Attribute</b>:</p>
            <tabular>
               <head length="2">
                  <column title="Instruktion"/>
                  <column title="Funktion"/>
               </head>
               <body>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc5.html#getfield">
                           <code>getfield</code>
                        </a>
                     </cell>
                     <cell>Legt Attributinhalt eines Objekts auf Operanden-Stack ab.<br/>
                        <small>Die Klasse des Objekts, auf das der Zugriff erfolgen soll, wird über einen 16-Bit Offset auf dem <a href="#runtimeConstantPool">runtime constant pool</a> addressiert. Auch hier wird wieder die Limitierung der virtuellen Maschine auf 2<sup>16</sup> Klassen deutlich.</small>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc5.html#getstatic">
                           <code>getstatic</code>
                        </a>
                     </cell>
                     <cell>Legt Attributinhalt eines statischen Klassenattributes auf dem Operanden-Stack ab.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc11.html#putfield">
                           <code>putfield</code>
                        </a>
                     </cell>
                     <cell>Setzt Wert eines Attributs.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc11.html#putstatic">
                           <code>putstatic</code>
                        </a>
                     </cell>
                     <cell>Setzt Wert eines statischen Klassenattributes.</cell>
                  </row>
               </body>
            </tabular>
            <p>
               <b>Instruktionen zur Operation auf Arrays</b>:</p>
            <tabular>
               <head length="2">
                  <column title="Instruktion"/>
                  <column title="Funktion"/>
               </head>
               <body>
                  <row>
                     <cell>
                        <a name="newarray" fixedType="JavaJVM" offset="Instructions2.doc10.html#newarray">
                           <code>newarray</code>
                        </a>
                     </cell>
                     <cell>Erzeugt einen neuen Array, und definiert die Komponententypen als einen der <a href="#Typsystem">Primitvtypen</a>.<br/>
         Die Implementierung von SUN verwendet für den Wahrheitswert je acht Bit. Anderen Umsetzungen ist es explizit Freigestellt hier mit optimierteren Speicherstrukturen zu operieren.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc2.html#anewarray">
                           <code>anewarray</code>
                        </a>
                     </cell>
                     <cell>Erzeugt einen neuen Array von Referenztypen zur Aufnahme beliebiger Objekte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a name="multianewarray" fixedType="JavaJVM" offset="Instructions2.doc9.html#multianewarray">
                           <code>multianewarray</code>
                        </a>
                     </cell>
                     <cell>Erzeugt einen mehrdimensionalen Array.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc.html#aaload">
                           <code>aaload</code>
                        </a>
                     </cell>
                     <cell>Lädt Referenz von Arrayposition.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc.html#aastore">
                           <code>aastore</code>
                        </a>
                     </cell>
                     <cell>Speicher Objekt an spezifischer Arrayposition.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc.html#arraylength">
                           <code>arraylength</code>
                        </a>
                     </cell>
                     <cell>Liefert Elementanzahl (Kardinalität) eines Arrays.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc1.html#baload">
                           <code>baload</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>byte</code> oder <code>boolean</code> aus Arrayposition.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc1.html#bastore">
                           <code>bastore</code>
                        </a>
                     </cell>
                     <cell>Legt <code>byte</code> oder <code>boolean</code> an Arrayposition ab.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc13.html#saload">
                           <code>saload</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>short</code> aus Arrayposition.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc13.html#sastore">
                           <code>sastore</code>
                        </a>
                     </cell>
                     <cell>Legt <code>short</code> an Arrayposition ab.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc2.html#caload">
                           <code>caload</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>char</code> aus Arrayposition.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc2.html#castore">
                           <code>castore</code>
                        </a>
                     </cell>
                     <cell>Legt <code>char</code> an Arrayposition ab.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#daload">
                           <code>daload</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>double</code> aus Arrayposition.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dastore">
                           <code>dastore</code>
                        </a>
                     </cell>
                     <cell>Legt <code>double</code> an Arrayposition ab.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#faload">
                           <code>faload</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>float</code> aus Arrayposition.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#fastore">
                           <code>fastore</code>
                        </a>
                     </cell>
                     <cell>Legt <code>float</code> an Arrayposition ab.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#iaload">
                           <code>iaload</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>int</code> aus Arrayposition.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#iastore">
                           <code>iastore</code>
                        </a>
                     </cell>
                     <cell>Legt <code>int</code> an Arrayposition ab.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#laload">
                           <code>laload</code>
                        </a>
                     </cell>
                     <cell>Lädt <code>long</code> aus Arrayposition.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lastore">
                           <code>lastore</code>
                        </a>
                     </cell>
                     <cell>Legt <code>long</code> an Arrayposition ab.</cell>
                  </row>
               </body>
            </tabular>
            <p>
               <b>Instruktionen zur Typkonversion</b>:</p>
            <tabular>
               <head length="2">
                  <column title="Instruktion"/>
                  <column title="Funktion"/>
               </head>
               <body>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#i2b">
                           <code>i2b</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>int</code> zu <code>byte</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#i2c">
                           <code>i2c</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>int</code> zu <code>char</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#i2d">
                           <code>i2d</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>int</code> zu <code>double</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#i2f">
                           <code>i2f</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>int</code> zu <code>float</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#i2l">
                           <code>i2l</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>int</code> zu <code>long</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#i2s">
                           <code>i2s</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>int</code> zu <code>short</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#d2f">
                           <code>d2f</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>double</code> zu <code>float</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#l2d">
                           <code>l2d</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>long</code> zu <code>double</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#l2f">
                           <code>l2f</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>long</code> zu <code>float</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#l2i">
                           <code>l2i</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>long</code> zu <code>int</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#d2f">
                           <code>d2f</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>double</code> zu <code>float</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#f2d">
                           <code>f2d</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>float</code> zu <code>double</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#f2i">
                           <code>f2i</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>float</code> zu <code>int</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#f2l">
                           <code>f2l</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>float</code> zu <code>long</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#d2f">
                           <code>d2f</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>double</code> zu <code>float</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#d2f">
                           <code>d2f</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>double</code> zu <code>float</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#d2i">
                           <code>d2i</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>double</code> zu <code>int</code>.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#d2l">
                           <code>d2l</code>
                        </a>
                     </cell>
                     <cell>Konvertiert <code>double</code> zu <code>long</code>.</cell>
                  </row>
               </body>
            </tabular>
            <p>
               <b>Instruktionen zur Durchführung arithmetischer Operationen</b>:<br/>
Eingangsperanden werden vom Stack entnommen und das Berechnungsergebnis ebenda abgelegt.</p>
            <tabular>
               <head length="2">
                  <column title="Instruktion"/>
                  <column title="Funktion"/>
               </head>
               <body>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dadd">
                           <code>dadd</code>
                        </a>
                     </cell>
                     <cell>Addiert zwei <code>double</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dsub">
                           <code>dsub</code>
                        </a>
                     </cell>
                     <cell>Subtrahiert zwei <code>double</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#ddiv">
                           <code>ddiv</code>
                        </a>
                     </cell>
                     <cell>Dividiert zwei <code>double</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dmul">
                           <code>dmul</code>
                        </a>
                     </cell>
                     <cell>Multipliziert zwei <code>double</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dneg">
                           <code>dneg</code>
                        </a>
                     </cell>
                     <cell>Negiert <code>double</code>-Wert durch Zweierkomplementbildung.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#drem">
                           <code>drem</code>
                        </a>
                     </cell>
                     <cell>Divisionsrest bei Division zweier <code>double</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc3.html#dcmpop">
                           <code>dcmp<em>&lt;op&gt;</em>
                           </code>
                        </a>
                     </cell>
                     <cell>Vergleicht zwei double Werte.<br/>
         Ist einer der beiden Operanden <code>NaN</code>, so legt <code>dcmpg</code>
                        <code>1</code>, <code>dcmpl</code> hingegen <code>-1</code> als Ergebnis auf dem Stack ab.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#fadd">
                           <code>fadd</code>
                        </a>
                     </cell>
                     <cell>Addiert zwei <code>float</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#fsub">
                           <code>fsub</code>
                        </a>
                     </cell>
                     <cell>Subtrahiert zwei <code>float</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#fmul">
                           <code>fmul</code>
                        </a>
                     </cell>
                     <cell>Multipliziert zwei <code>float</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#fdiv">
                           <code>fdiv</code>
                        </a>
                     </cell>
                     <cell>Dividiert zwei <code>float</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#iadd">
                           <code>iadd</code>
                        </a>
                     </cell>
                     <cell>Addiert zwei <code>int</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#isub">
                           <code>isub</code>
                        </a>
                     </cell>
                     <cell>Subtrahiert zwei <code>int</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#imul">
                           <code>imul</code>
                        </a>
                     </cell>
                     <cell>Multipliziert zwei <code>int</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#idiv">
                           <code>idiv</code>
                        </a>
                     </cell>
                     <cell>Dividiert zwei <code>int</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#iand">
                           <code>iand</code>
                        </a>
                     </cell>
                     <cell>Boole'sche UND-Verknüpfung zweier <code>int</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#ior">
                           <code>ior</code>
                        </a>
                     </cell>
                     <cell>Boole'sche ODER-Verknüpfung zweier <code>int</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#ixor">
                           <code>ixor</code>
                        </a>
                     </cell>
                     <cell>Exklusive Boole'sche ODER-Verknüpfung zweier <code>int</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#ineg">
                           <code>ineg</code>
                        </a>
                     </cell>
                     <cell>Negiert <code>int</code>-Wert durch Zweierkomplementbildung.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#irem">
                           <code>irem</code>
                        </a>
                     </cell>
                     <cell>Divisionsrest bei Division zweier <code>int</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#ishl">
                           <code>ishl</code>
                        </a>
                     </cell>
                     <cell>Linksshift eines <code>int</code>-Wertes.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#ishr">
                           <code>ishr</code>
                        </a>
                     </cell>
                     <cell>Rechtsshift eines <code>int</code>-Wertes.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc6.html#iushr">
                           <code>iushr</code>
                        </a>
                     </cell>
                     <cell>Rechtsshift eines <code>int</code>-Wertes unter Nulleinfügung und Vorzeichenlösung.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#fneg">
                           <code>fneg</code>
                        </a>
                     </cell>
                     <cell>Negiert <code>float</code>-Wert durch Zweierkomplementbildung.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#frem">
                           <code>frem</code>
                        </a>
                     </cell>
                     <cell>Divisionsrest bei Division zweier <code>float</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc4.html#fcmpop">
                           <code>fcmp<em>&lt;op&gt;</em>
                           </code>
                        </a>
                     </cell>
                     <cell>Vergleicht zwei <code>float</code>Werte.<br/>
         Ist einer der beiden Operanden <code>NaN</code>, so legt <code>fcmpg</code>
                        <code>1</code>, <code>fcmpl</code> hingegen <code>-1</code> als Ergebnis auf dem Stack ab.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#ladd">
                           <code>ladd</code>
                        </a>
                     </cell>
                     <cell>Addiert zwei <code>long</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#land">
                           <code>land</code>
                        </a>
                     </cell>
                     <cell>Boole'sche UND-Verknüpfung zweier <code>long</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lcmp">
                           <code>ldcmp</code>
                        </a>
                     </cell>
                     <cell>Vergleicht zwei <code>long</code>Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#ldiv">
                           <code>ldiv</code>
                        </a>
                     </cell>
                     <cell>Dividiert zwei <code>long</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lmul">
                           <code>lmul</code>
                        </a>
                     </cell>
                     <cell>Multipliziert zwei <code>long</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lneg">
                           <code>lneg</code>
                        </a>
                     </cell>
                     <cell>Negiert <code>long</code>-Wert durch Zweierkomplementbildung.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lrem">
                           <code>lrem</code>
                        </a>
                     </cell>
                     <cell>Divisionsrest bei Division zweier <code>long</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lor">
                           <code>lor</code>
                        </a>
                     </cell>
                     <cell>Boole'sche ODER-Verknüpfung zweier <code>long</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lshl">
                           <code>lshl</code>
                        </a>
                     </cell>
                     <cell>Linksshift eines <code>long</code>-Wertes.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lshr">
                           <code>lshr</code>
                        </a>
                     </cell>
                     <cell>Rechtsshift eines <code>long</code>-Wertes.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lsub">
                           <code>lsub</code>
                        </a>
                     </cell>
                     <cell>Subtrahiert zwei <code>long</code>-Werte.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lushr">
                           <code>lushr</code>
                        </a>
                     </cell>
                     <cell>Rechtsshift eines <code>long</code>-Wertes unter Nulleinfügung und Vorzeichenlösung.</cell>
                  </row>
                  <row>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc8.html#lxor">
                           <code>lxor</code>
                        </a>
                     </cell>
                     <cell>Exklusive Boole'sche ODER-Verknüpfung zweier <code>long</code>-Werte.</cell>
                  </row>
               </body>
            </tabular>
            <p>
               <b>Sonstige Instruktionen</b>:</p>
            <tabular>
               <head length="2">
                  <column title="Instruktion"/>
                  <column title="Funktion"/>
               </head>
               <body>
                  <row>
                     <cell>Ausnahmebehandlung</cell>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc.html#athrow">
                           <code>athrow</code>
                        </a>
                     </cell>
                     <cell>Wirft eine Exception.</cell>
                  </row>
                  <row>
                     <cell>
                        <a name="monitoroperationen">Synchronisation -- Monitoroperationen</a>
                     </cell>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc9.html#monitorenter">
                           <code>monitorenter</code>
                        </a>
                     </cell>
                     <cell>Der Zugriff auf jedes Objekt wird durch einen Monitor synchronisiert. Die Anweisung sperrt ein Objekt.</cell>
                  </row>
                  <row>
                     <cell/>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc9.html#monitorexit">
                           <code>monitorexit</code>
                        </a>
                     </cell>
                     <cell>Gibt ein gesperrtes Objekt frei.</cell>
                  </row>
                  <row>
                     <cell>Sonstige Opcodes</cell>
                     <cell>
                        <a fixedType="JavaJVM" offset="Instructions2.doc10.html#nop">
                           <code>nop</code>
                        </a>
                     </cell>
                     <cell>Buchstäblich: <em>no operation</em>. Bewirkt nichts; keine Operatoren, keine Änderungen am Operanden-Stack.</cell>
                  </row>
               </body>
            </tabular>
            <p>Die beiden Opcodes mit den Ordnungsnummern 254 und 255 (0xfe und 0xff, mnemonic <code>impdep1</code> und <code>impdep2</code>) sind durch SUN als reserviert gekennzeichnet. Sie können von durch den Hersteller der virtuellen Maschine mit eigendefinierter Funktionalität implementiert werden.<br/>
Darüberhinaus ist mit dem Opcode 202 (mnemonic <code>breakpoint</code>) ein Einstiegspunkt für Debugger definiert.</p>
            <p>Alle Opcodes sind mit einem Byte codiert. Hieraus ergibt 256 als maximaler Befehlsumfang der virtuellen Maschine. Zur Verringerung der notwendigen verschiedenen Befehle sind nicht alle Opcodes für alle <a href="#JVMTypsystem">Typen der JVM</a> implementiert. Üblicherweise existieren nur Opcodes für <code>int</code>, <code>float</code>, <code>long</code> und <code>double</code> sowie die Referenzen. Für alle anderen Typen stehen Konvertierungsmöglichkeiten in die genannten zur Verfügung.</p>
            <tabular>
               <head length="9">
                  <column title="Opcode"/>
                  <column title="byte"/>
                  <column title="short"/>
                  <column title="int"/>
                  <column title="long"/>
                  <column title="float"/>
                  <column title="double"/>
                  <column title="char"/>
                  <column title="Referenz"/>
               </head>
               <body>
                  <row>
                     <cell>
                        <code>...ipush</code>
                     </cell>
                     <cell>
                        <code>bipush</code>
                     </cell>
                     <cell>
                        <code>sipush</code>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...const</code>
                     </cell>
                     <cell/>
                     <cell/>
                     <cell>
                        <code>iconst</code>
                     </cell>
                     <cell>
                        <code>lconst</code>
                     </cell>
                     <cell>
                        <code>fconst</code>
                     </cell>
                     <cell>
                        <code>dconst</code>
                     </cell>
                     <cell/>
                     <cell>
                        <code>aconst</code>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...load</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>iload</code>
                     </cell>
                     <cell>
                        <code>lload</code>
                     </cell>
                     <cell>
                        <code>fload</code>
                     </cell>
                     <cell>
                        <code>dload</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>aload</code>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...store</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>istore</code>
                     </cell>
                     <cell>
                        <code>lstore</code>
                     </cell>
                     <cell>
                        <code>fstore</code>
                     </cell>
                     <cell>
                        <code>dstore</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>astore</code>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...inc</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>iinc</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...aload</code>
                     </cell>
                     <cell>
                        <code>baload</code>
                     </cell>
                     <cell>
                        <code>saload</code>
                     </cell>
                     <cell>
                        <code>iaload</code>
                     </cell>
                     <cell>
                        <code>laload</code>
                     </cell>
                     <cell>
                        <code>faload</code>
                     </cell>
                     <cell>
                        <code>daload</code>
                     </cell>
                     <cell>
                        <code>caload</code>
                     </cell>
                     <cell>
                        <code>aaload</code>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...astore</code>
                     </cell>
                     <cell>
                        <code>bastore</code>
                     </cell>
                     <cell>
                        <code>sastore</code>
                     </cell>
                     <cell>
                        <code>iastore</code>
                     </cell>
                     <cell>
                        <code>lastore</code>
                     </cell>
                     <cell>
                        <code>fastore</code>
                     </cell>
                     <cell>
                        <code>dastore</code>
                     </cell>
                     <cell>
                        <code>castore</code>
                     </cell>
                     <cell>
                        <code>aastore</code>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...add</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>iadd</code>
                     </cell>
                     <cell>
                        <code>ladd</code>
                     </cell>
                     <cell>
                        <code>fadd</code>
                     </cell>
                     <cell>
                        <code>dadd</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...sub</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>isubb</code>
                     </cell>
                     <cell>
                        <code>lsub</code>
                     </cell>
                     <cell>
                        <code>fsub</code>
                     </cell>
                     <cell>
                        <code>dsub</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...mul</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>imul</code>
                     </cell>
                     <cell>
                        <code>lmul</code>
                     </cell>
                     <cell>
                        <code>fmul</code>
                     </cell>
                     <cell>
                        <code>dmul</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...div</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>idiv</code>
                     </cell>
                     <cell>
                        <code>ldiv</code>
                     </cell>
                     <cell>
                        <code>fdiv</code>
                     </cell>
                     <cell>
                        <code>ddiv</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...rem</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>irem</code>
                     </cell>
                     <cell>
                        <code>lrem</code>
                     </cell>
                     <cell>
                        <code>frem</code>
                     </cell>
                     <cell>
                        <code>drem</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...neg</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>ineg</code>
                     </cell>
                     <cell>
                        <code>lneg</code>
                     </cell>
                     <cell>
                        <code>fneg</code>
                     </cell>
                     <cell>
                        <code>dneg</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...shl</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>ishl</code>
                     </cell>
                     <cell>
                        <code>lshl</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...shr</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>ishr</code>
                     </cell>
                     <cell>
                        <code>lshr</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...ushr</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>iushr</code>
                     </cell>
                     <cell>
                        <code>lushr</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...and</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>iand</code>
                     </cell>
                     <cell>
                        <code>land</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...or</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>ior</code>
                     </cell>
                     <cell>
                        <code>lor</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...xor</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>ixor</code>
                     </cell>
                     <cell>
                        <code>lxor</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>i2...</code>
                     </cell>
                     <cell>
                        <code>i2b</code>
                     </cell>
                     <cell>
                        <code>i2s</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>i2l</code>
                     </cell>
                     <cell>
                        <code>i2f</code>
                     </cell>
                     <cell>
                        <code>i2d</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>l2...</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>l2i</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>l2f</code>
                     </cell>
                     <cell>
                        <code>l2d</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>f2...</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>f2i</code>
                     </cell>
                     <cell>
                        <code>f2l</code>
                     </cell>
                     <cell>
                        <code>f2d</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...cmp</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>lcmp</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...cmpl</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>fcmpl</code>
                     </cell>
                     <cell>
                        <code>dcmpl</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...cmpg</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>fcmpg</code>
                     </cell>
                     <cell>
                        <code>dcmpg</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>if_...cmp<em>cond</em>
                        </code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>if_icmp<em>cond</em>
                        </code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>if_acmp<em>cond</em>
                        </code>
                     </cell>
                  </row>
                  <row>
                     <cell>
                        <code>...return</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>ireturn</code>
                     </cell>
                     <cell>
                        <code>lreturn</code>
                     </cell>
                     <cell>
                        <code>freturn</code>
                     </cell>
                     <cell>
                        <code>dreturn</code>
                     </cell>
                     <cell>
                        <code/>
                     </cell>
                     <cell>
                        <code>areturn</code>
                     </cell>
                  </row>
               </body>
            </tabular>
            <p>
               <a name="OpcodeException">Treten</a> bei der Ausführung der Opcodes Ausnahmen auf, so werden durch die virtuelle Maschine <a fixedType="JavaAPI" offset="java\lang\RuntimeException.html">Laufzeit-Ausnahmeereignisse</a> (engl. <em>runtime exception</em>) generiert. <a href="#runtimeException">Wie bekannt</a> werden Ausnahmen dieser Kategorie (üblicherweise) nicht aufgefangen und behandelt.<br/>
So wird die <a fixedType="JavaAPI" offset="java/lang/ClassCastException.html">
                  <code>ClassCastException</code>
               </a> im <a href="#ClassCastException">Beispiel aus Kapitel 2</a> durch die versuchte explizite Typumwandlung ausgelöst.<br/>
Der erzeugte Bytecode für diese Anweisung lautet:</p>
            <verbatim>aload_3
checkcast 2</verbatim>
            <p>
               <code>aload_3</code> lädt die Referenz auf eine lokale Variable auf den Operanden-Stack. Die lokale Variable 3 entspricht im Beispiel <code>myC11</code>.<br/>
               <code>checkcast</code> testet ob die auf dem Operanden-Stack befindliche Referenz kompatibel zum übergebenen Typen (hier die 2 als Referenz auf die zweite geladene Klasse; benannt mit <code>C2</code>) ist. Im Falle der Nichtkompatibilität wird durch die virtuelle Maschine eine <code>ClassCastException</code> erzeugt.</p>
            <scriptElement type="example" name="BC1" title="Einfache arithmetische und Ein-/Ausgabeoperationen" filename="BC1.j">
               <importText URI="../development/vorlesung/sharedScriptParts/JVM/BC1.j"/>
            </scriptElement>
            <p>Der Java-Assemblercode des Beispiels <scriptRef type="example" name="BC1"/> zeigt die Verwendung einiger einfacher arithmetischer und Ein-/Ausgabeoperationen.<br/>
Zunächst zeigt das Beispiel den Aufbau einer Java-Assemblerdatei, wie sie vom Übersetzer <a href="http://mrl.nyu.edu/~meyer/jasmin/">
                  <em>Jasmin</em>
               </a> akzeptiert und in ausführbaren Java-Bytecode umgewandelt wird.<br/>
So legt die <code>.class</code>-Deklaration zunächst fest, daß es sich um die öffentlich zugängliche (d.h. als <code>public</code> deklarierte) Klasse <code>BC1</code>, im Paket <code>examples</code> handelt.<br/>
Die darauf folgende <code>.super</code>-Definition legt die Elternklasse der betrachteten Klasse fest. Im Falle keiner explizit definierten Elternklasse ist dies vorgabegemäß die Standardklasse <a fixedType="JDKcurrent" offset="java/lang/Class.html" keyword="yes">Class</a>.<br/>
Nach den einführenden Deklarationen definiert die Quellcodedatei den statischen Initialisierter.</p>
            <p>Die Methode <code>main</code> stellt den Beginn der aktiven Verarbeitung dar. Ihre Signaturdefinition <code>([Ljava/lang/String;)V</code> läßt die JVM-interne Kurzschreibweise des Typsystems erkennen. So deutet die in den Klammern der Übergabewerte eingeschlossene eckige Klammern an, daß ein Array gleichtypisierter Ausprägungen übergeben wird. Diese Ausprägungen sind alle vom Standardtyp <code>java.lang.String</code> (die paket-separierenden Punkte werden JVM-intern zu Pfadseparatoren aufgelöst). Zusätzlich ist dem Klassenname ein einleitendes <code>L</code> vorangestellt, um auszudrücken, daß es sich nicht um einen Primitivtyp, sondern um eine Sprachkomponente (das <gerquot>L</gerquot> deutet hierbei auf den Begriff <em>language</em> hin) handelt.<br/>
Nach der Klammer ist der Rückgabetyp --- im Falle von <code>main</code> vorgabegemäß <code>void</code> --- angegeben. Auch er wird unter Verwendung derselben Abkürzungskonvention dargestellt.</p>
            <p>Zu Eingangs der Methode <code>main</code> allozieren die beiden Direktiven <code>.limit</code> zunächst Speicher für die lokalen Variablen (<code>.limit locals</code>) und die Tiefe des methodenintern verwendeten Operandenstacks (<code>.limit stack</code>).</p>
            <p>Die (aktive durch den Programmierer gesteuerte) Verarbeitung beginnt im Beispiel mit dem Anweisung <code>iconst_2</code> welche den ganzzahligen Wert 2 auf dem Operandenstack ablegt. Anschließend wird dieser Wert, mittels der Anweisung <code>istore_0</code> vom Stack entnommen und in die erste lokale Variable gespeichert.<br/>
Mit <a offset="Instructions2.doc7.html" fixedType="JavaJVM" keyword="yes">iconst_2</a> findet ein besonderer Befehl zur Ablage einer ganzzahligen Konstante auf dem Operanden Stack Verwendung, der es gestattet bestimmte (häufig benötigte) Konstantenablagen in nur genau einem Byte auszudrücken. Durch die JVM-Spezifikation vorgesehen sind hierbei Instruktionen für die Konstanten <code>-1, 0, 1, 2, 3, 4 oder 5</code>. Im Ergebnis ist die Nutzung der abkürzenden Befehlsschweibweise äquivalent zum Einsatz der Instruktion <a fixedType="JavaJVM" offset="Instructions2.doc1.html" keyword="yes">bipush</a> unter Explizierung der abzulegenden Konstante.</p>
            <p>Diese äquivalente Form der Belegung einer lokalen Variable zeigt der zweite Anweisungsblock, der die numerische Konstante <code>101</code>, für die keine abkürzende Schreiweise angeboten wird, auf dem Operandenstack ablegt um sie der zweiten lokalen Variable (mit der Indexnummer 1) zuzuweisen.<br/>
In derselben Weise wird für die Initialisierung der dritten lokalen Variablen mit dem Wert <code>99</code> verfahren.</p>
            <p>Anschließend wird durch <code>getstatic</code> der Dateideskriptor der Standardausgabe (d.h. desjenigen Streams mit dem Wert <code>System/out</code>) gelesen und die zurückgelieferte Adresse in der vierten lokalen Variable (Indexnummer 3) abgelegt.</p>
            <p>Der darauffolgende Anweisungsblock zeigt die Umsetzung einer einfachen Ganzzahladdition, die zunächst die beiden zu verknüpfenden Operanden (die Inhalte der lokalen Variablen mit den Indexnummern 1 und 2) auf dem Stack ablegt und anschließend mittels der Ganzzahladdition (<a offset="Instructions2.doc6.html" fixedType="javaJVM" keyword="yes">iadd</a>) verknüpft.<br/>
Das auf dem Stack abgelegte Berechnungsergebnis wird durch <code>istore_1</code> er zweiten lokalen Variablen zugewiesen.</p>
            <p>Der nächste Anweisungsblock bereitet die Ausgabe des Berechnungsergebnisses auf der Standardausgabe vor.<br/>
Hierzu plaziert er zunächst den Inhalt der lokalen Variable mit der Indexnummer 1 (d.h. das Berechnungsergebnis des direkt vorhergehenden Schrittes) auf dem Stack. <br/>
Anschließend wird eine Standard-API-Methode (die Methode <a fixedType="JDKcurrent" offset="java/lang/String.html#valueOf(int)" keyword="yes">valueOf</a>) aufgerufen, welche den auf dem Stack übergebenen int-Parameter in eine Zeichenkette wandelt und die Referenz darauf als Rückgabewert auf dem Stack plaziert.<br/>
Dieser Rückgabewert wird in der fünften lokalen Variable (Indexnummer 4) abgelegt.</p>
            <p>Anschließend werden die in zwischenzeitlich den vierten und fünften lokalen Variablen abgelegten Adressen des Ausgabe-Streams und der auszugebenden Zeichenkette geladen und auf dem Operanden-Stack abgelegt.<br/>
Durch Aufruf der Standard-Ausgabemethode <a fixedType="JDKcurrent" offset="java/io/PrintStream.html#println(java.lang.String)" keyword="yes">println</a> mittels <a fixedType="JavaJVM" offset="Instructions2.doc6.html" keyword="yes">invokevirtual</a> wird die referenzierte Zeichenkette auf der Standardausgabe dargestellt.</p>
            <p>Der folgende Anweisungsblock demonstriert eine Ganzzahldivision mittels <a fixedType="JavaJVM" offset="Instructions2.doc6.html" keyword="yes">idiv</a> welche Divisior und Dividenden als Operadnen auf dem Stack erwartet und das Berechnungsergebnis ebenda plaziert.</p>
            <p>Anschließend wird das (noch auf dem Stack liegende) Berechnungsergebnis direkt weiterverarbeitet und in eine Zeichenkette gewandelt. Hierbei kommt die bereits bekannte Funktion zum Einsatz.<br/>
Danach erfolgt wiederum die Ausgabe in der bekannten Form.</p>
            <p>Abschließend wird eine fixe Zeichenkette ausgegeben, deren Zeichenkettendarstellung nicht berechnet zu werden braucht. Ihr Wert kann daher direkt aus dem Laufzeitkonstantenpool per <a fixedType="JavaJVM" offset="Instructions2.doc8.html" keyword="yes">ldc</a> geladen werden.<br/>
Die übrigen Schritte zur Erzeugung der Ausgabe bleiben indes unverändert.</p>
            <p>
               <b>Nutzung von Methoden</b>:<br/>
Bereits bei den einfachen Operationen aus Beispiel <scriptRef type="example" name="BC1"/> zeigt sich, daß die wiederholte Angabe von sehr ähnlichen Instruktionsfolgen nicht zu vermeiden ist. Insbesondere die beiden Konversionen des <code>int</code>-Datentyps als Voraussetzung der zeichenbasierten Ausgabe ist vollständig identisch.<br/>
Zur Strukturierung stehen daher auf der Java-Assemblerebene die bereits aus der Java-Hochsprache bekannten <em>Methoden</em> zur Verfügung, wie Beispiel <scriptRef type="example" name="BC2"/> zeigt.</p>
            <scriptElement type="example" name="BC2" title="Nutzun von Methoden" filename="BC2.j">
               <importText URI="../development/vorlesung/sharedScriptParts/JVM/BC2.j"/>
            </scriptElement>
            <p>Die Funktionalität des Beispieles ist mit der der vorhergend vorgestellten Codesequenz identisch. Jedoch finden sich jetzt die Instruktionsfolgen zur Berechnung der Zeichenkettenrepräsentation einer Ganzzahl und ihrer anschließenden Ausgabe in die Methode <code>printInt</code> ausgelagert.</p>
            <p>Diese Methode akzeptiert eine Ausprägung des Primitivtyps <code>int</code> als Übergabe und liefert keinen Rückgabewert.<br/>
Die Signatur ist daher dahingehend vereinbart, daß genau eine <code>int</code>-konforme Zahl als Parameter auf dem Stack erwartet wird, d.h. der Aufrufer hat diese vor dem Aufruf dort abzulegen.</p>
            <p>Zusätzlich benötigt die Methode selbst zu ihrer Ausführung einige lokale Variablen, die auf dem methodenspezifischen Stack abgelegt werden. Dieser stellt eine Erweiterung des bereits durch den Aufruf verwendeten Operandenstacks dar.</p>
            <p>Mit Java steht jedoch keineswegs die einzige Hochsprache zur Erzeugung von Byte-Code-Dateien zur Verfügung. <a href="http://grunge.cs.tu-berlin.de/~tolk/vmlanguages.html">Diese Seite</a> listet eine Vielzahl verschiedener Alternativen.<br/>
Beispielsweise erzeugt der <a href="http://www.mhccorp.com">Oberon-Compiler von Canterbury</a> für alle Oberon-Module, einschließlich der Systemmodule, Java-Klassen.</p>
            <scriptElement type="example" name="OberonHW" title="Die Hello World Applikation als Oberon Programm" filename="helloworld.obn">
               <code>
                  <pre>MODULE helloworld;

IMPORT Out;

BEGIN
  Out.String( "Hello World" );
  Out.Ln;
END helloworld.</pre>
               </code>
            </scriptElement>
            <p>Die erzeugten <code>class</code>-Dateien -- <a href="examples/Oberon/SYSTEM.class">SYSTEM.class</a>, <a href="examples/Oberon/helloworld.class">helloworld.class</a>, <a href="examples/Oberon/Out.class">Out.class</a>, <a href="examples/Oberon/Sys.class">Sys.class</a> -- können auf jeder JVM zur Ausführung gebracht werden. <code>java helloworld</code> liefert das erwartete Ergebnis.</p>
            <separator/>
            <p>Das <b>
                  <a name="classFileFormat">Class-File-Format</a>
               </b>
            </p>
            <p>Ausgangspunkt jeder Programmausführung innerhalb der JVM ist die <code>class</code>-Datei als Eingabe. Sie wird üblicherweise durch durch den Java-Compiler (im JDK: <a href="#javac">
                  <code>javac</code>
               </a> erzeugt).</p>
            <p>Einige Eigenschaften jedes <code>class</code>-Files:</p>
            <ul>
               <li>Es enthält die Definition genau einer Klasse oder einer Schnittstelle, unabhängig von deren Zugriffs- und Sichtbarkeitseigenschaften.</li>
               <li>Es wird als Bytestrom aufgefaßt, daher werden alle größeren Informationseinheiten durch serielles Lesen und aneinanderfügen gebildet.<br/>
   Unabhängig von der physischen Realisierung der tatsächlich zugrundeliegenden Hardware werden alle Multibyte-Daten im <em>big endian</em>-Format, d.h. größere Einheiten werden durch Linksshift und Boole'sches ODER gebildet, abgelegt.<br/>
                  <small>Die Schnittstellen <a fixedType="JavaAPI" offset="java/io/DataInput.html">
                        <code>java.io.DataInput</code>
                     </a>, <a fixedType="JavaAPI" offset="java/io/DataOutput.html">
                        <code>java.io.DataOutput</code>
                     </a>, <a fixedType="JavaAPI" offset="java/io/DataInputStream.html">
                        <code>java.io.DataInputStream</code>
                     </a> und <a fixedType="JavaAPI" offset="java/io/DataOutputStream.html">
                        <code>java.io.DataOutputStream</code>
                     </a> unterstützen dieses Format.</small> (<a href="#synchronized">Beispiel</a>)</li>
               <li>Die Strukturen innerhalb der <code>class</code>-Datei werden nicht zusätzlich optimiert abgelegt, daher erfolgt weder ein Auffüllen auf spezifische Wortgrenzen, noch ein Alignment an solchen.</li>
            </ul>
            <p>Die JVM-Spezifikation legt zur Definition der Struktur des <code>class</code>-Files <a fixedType="JavaJVM" offset="ClassFile.doc.html">eigene Datentypen</a> fest: <code>u1</code>, <code>u2</code> und <code>u4</code> zur Definition vorzeichenloser ein-, zwei- und drei-Bytetypen. Für diese (von der Java-üblichen vorzeichenbehafteten Mimik (abgesehen von <code>char</code>) abweichenden) Datentypen stehen mit <a fixedType="JavaAPI" offset="java/io/DataInput.html#readUnsignedByte()">
                  <code>readUnsignedByte()</code>
               </a>, <a fixedType="JavaAPI" offset="java/io/DataInput.html#readUnsignedShort()">
                  <code>readUnsignedShort()</code>
               </a> und <a fixedType="JavaAPI" offset="java/io/DataInput.html#readInt()">
                  <code>readInt()</code>
               </a> entsprechende Lesemethoden zur Verfügung.</p>
            <p>
               <a fixedType="JavaJVM" offset="ClassFile.doc.html#74353">The <code>class</code> File Format @ Java Virtual Machine Specification</a>
            </p>
            <verbatim>ClassFile {
      u4 magic;
      u2 minor_version;
      u2 major_version;
      u2 constant_pool_count;
      cp_info constant_pool[constant_pool_count-1];
      u2 access_flags;
      u2 this_class;
      u2 super_class;
      u2 interfaces_count;
      u2 interfaces[interfaces_count];
      u2 fields_count;
      field_info fields[fields_count];
      u2 methods_count;
      method_info methods[methods_count];
      u2 attributes_count;
      attribute_info attributes[attributes_count];
    }</verbatim>
            <p>
               <a fixedType="JavaJVM" offset="ClassFile.doc.html#9597">Constant Pool @ Java Virtual Machine Specification</a>
            </p>
            <verbatim>cp_info {
      u1 tag;
      u1 info[];
    }</verbatim>
            <p>
               <a fixedType="JavaJVM" offset="ClassFile.doc.html#2877">
                  <code>field_info</code> @ Java Virtual Machine Specification</a>
            </p>
            <verbatim>field_info {
        u2 access_flags;
        u2 name_index;
        u2 descriptor_index;
        u2 attributes_count;
        attribute_info attributes[attributes_count];
           }</verbatim>
            <p>
               <a fixedType="JavaJVM" offset="ClassFile.doc.html#1515">
                  <code>method_info</code> @ Java Virtual Machine Specification</a>
            </p>
            <verbatim>method_info {
        u2 access_flags;
        u2 name_index;
        u2 descriptor_index;
        u2 attributes_count;
        attribute_info attributes[attributes_count];
    }</verbatim>
            <p>
               <a fixedType="JavaJVM" offset="ClassFile.doc.html#43817">
                  <code>attribute_info</code> @ Java Virtual Machine Specification</a>
            </p>
            <verbatim>  attribute_info {
        u2 attribute_name_index;
        u4 attribute_length;
        u1 info[attribute_length];
    }</verbatim>
            <p>Aufbau einer <code>class</code>-Datei verdeutlicht an nachfolgendem Beispielquellcode.</p>
            <p>
               <em>Hinweis</em>: Mit <em>
                  <a href="http://sourceforge.net/projects/classeditor/">Classeditor</a>
               </em> existiert ein freies Werkzeug zur Inspektion und Modifikation übersetzter Class-Dateien.</p>
            <scriptElement type="example" name="snippet" title="Java-Quellcode der untersuchten Klassendatei" filename="Snipet.java">
               <importText URI="../development/vorlesung/sharedScriptParts/JVM/Snipet.java"/>
            </scriptElement>
            <graphic src="java/cf1.gif" width="500" caption="magic Identifier" center="yes"/>
            <p>Der <code>magic</code>-Identifier ist auf die Bytekombination (in hexadezimaler Darstellung) <code>CA FE BA BE</code> fixiert. Anhand dieser erkennt der Kassenlader der Laufzeitsystems die Datei als ausführbare Java-Bytecode-Datei an.<br/>
Ist diese gegenüber dem Vorgabewert modifiziert wird eine <code>java.lang.ClassFormatError</code> Ausnahme im Hauptthread generiert (<code>Bad magic number</code> wird als zusätzliche Nachricht der Ausnahme ausgegeben).
<a fixedType="JavaJVM" offset="ClassFile.doc.html#19719">siehe JVM-Spezifikation</a>
            </p>
            <graphic width="500" src="java/cf2.gif" caption="version identifier" center="yes"/>
            <p>Die beiden Versionskennungen <code>minor</code> und <code>major</code> bilden gemeinsam den Versionsschlüssel der <code>class</code>-Datei in der gängigen Punktnotation. Hierbei gilt: <code>major</code>.<code>minor</code>
               <br/>
Die Klassendatei des Beispiels trägt den Versionsschlüssel <code>45.3</code>.<br/>
Der im SUN JDK enthaltene Java-Compiler erlaubt per Kommandozeilenparameter (<code>target</code>) die JVM-spezifische Steuerung der Codegenerierung. Die
den einzelnen Sprachversionen zugeordneten Bytecodeversionen sind in der nachfolgenden Tabelle zusammengestellt.</p>
            <tabular summary="Zusammenstellung der verschiedenen Bytecode- und zugehörigen Javaversionen">
               <head length="2">
                  <column title="Java-Version"/>
                  <column title="Bytecode-Version"/>
               </head>
               <body>
                  <row>
                     <cell>1.1</cell>
                     <cell>45.3</cell>
                  </row>
                  <row>
                     <cell>1.2</cell>
                     <cell>46.0</cell>
                  </row>
                  <row>
                     <cell>1.3</cell>
                     <cell>47.0</cell>
                  </row>
                  <row>
                     <cell>1.4 (sowie 1.4.1, 1.4.2 und der Prototyp des 1.5-Compilers)</cell>
                     <cell>48.0</cell>
                  </row>
                  <row>
                     <cell>Zweite Vorabversion des 1.5-Compilers</cell>
                     <cell>50.0</cell>
                  </row>
                  <row>
                     <cell>1.5 (beta1)</cell>
                     <cell>49.0</cell>
                  </row>
                  <row>
                     <cell>1.5 (beta2)</cell>
                     <cell>49.29</cell>
                  </row>
               </body>
            </tabular>
            <p>Vorgabegemäß wird durch die Compilerversion 1.5 (ab Beta-Version 2) <code>49.29</code> erzeugt.<br/>
Trägt eine <code>class</code>-Datei eine durch die JVM nicht unterstützte Versionsnummer, so wird eine <code>java.lang.UnsupportedClassVersionError</code>-Ausnahme generiert.<br/>
Jede JVM kann verschiedene <code>class</code>-Datei-Versionen unterstützen, die letzendlich Festlegung welche Versionen durch einzelne Java-Plattform-Releases zu unterstützten sind obliegt jedoch SUN. So unterstützt SUNs JDK v1.0.2 <code>class</code>-Dateien der Versionen 45.0 bis einschließlich 45.3. Die JDK-Generation v1.1.x ab Version 45.0 bis einschließlich 45.65535 und Implementierungen der Java 2 Plattform, Version 1.2, bis einschließlich 46.0. JDK v1.3.0 verarbeitet Klassendateien bis hin zur Versionsnummer <code>47.0</code>. Zur Verarbeitung von Klassen, welche die in 1.5 eingeführten Generizitätsmechanismen verwenden nicht zwingend eine Ausführungsumgebung dieser Versionsnummer benötigt, da das erzeugte Klassenformat (bisher, da diese Aussagen auf dem Informationsstand der verfügbaren Betaversion basieren) nicht verändert wurde. Die Nutzung des dynamischen Boxing/Unboxings benötigt jedoch eine Ausführungsumgebung mindestens der Version 1.5.<br/>
               <a fixedType="JavaJVM" offset="ClassFile.doc.html#13448">siehe JVM-Spezifikation</a>
            </p>
            <graphic width="500" src="java/cf3.gif" caption="constant pool count" center="yes"/>
            <p>Die Bytefolge <code>constant_pool_count</code> enthält die um eins erhöhte Anzahl der Einträge der <code>constant_pool</code> Tabelle.<br/>
Im Beispiel ist dies: 17.<br/>
               <a fixedType="JavaJVM" offset="ClassFile.doc.html#31689">siehe JVM-Spezifikation</a>
            </p>
            <p>Der <code>constant pool</code> enthält die symbolische Information über Klassen, Schnittstellen, Objekte und Arrays. Die Elemente des dieser Datenstruktur sind vom Typ <code>cp_info</code> und variieren je nach <code>tag</code> in ihrer Länge. Als Konstantentypen (=Inhalt des Tag-Bytes) sind zugelassen:</p>
            <tabular>
               <head length="2">
                  <column title="Konstantentyp"/>
                  <column title="Wert"/>
               </head>
               <body>
                  <row>
                     <cell>
                        <code>CONSTANT_CLASS</code>
                     </cell>
                     <sortcell>7</sortcell>
                  </row>
                  <row>
                     <cell>
                        <code>CONSTANT_Fieldref</code>
                     </cell>
                     <sortcell>9</sortcell>
                  </row>
                  <row>
                     <cell>
                        <code>CONSTANT_Methodref</code>
                     </cell>
                     <sortcell>10</sortcell>
                  </row>
                  <row>
                     <cell>
                        <code>CONSTANT_InterfaceMethodref</code>
                     </cell>
                     <sortcell>11</sortcell>
                  </row>
                  <row>
                     <cell>
                        <code>CONSTANT_String</code>
                     </cell>
                     <sortcell>8</sortcell>
                  </row>
                  <row>
                     <cell>
                        <code>CONSTANT_Integer</code>
                     </cell>
                     <sortcell>3</sortcell>
                  </row>
                  <row>
                     <cell>
                        <code>CONSTANT_Float</code>
                     </cell>
                     <sortcell>4</sortcell>
                  </row>
                  <row>
                     <cell>
                        <code>CONSTANT_Long</code>
                     </cell>
                     <sortcell>5</sortcell>
                  </row>
                  <row>
                     <cell>
                        <code>CONSTANT_Double </code>
                     </cell>
                     <sortcell>6</sortcell>
                  </row>
                  <row>
                     <cell>
                        <code>CONSTANT_NameAndType</code>
                     </cell>
                     <sortcell>12</sortcell>
                  </row>
                  <row>
                     <cell>
                        <code>CONSTANT_Utf8</code>
                     </cell>
                     <sortcell>1</sortcell>
                  </row>
               </body>
            </tabular>
            <p>
               <a fixedType="JavaJVM" offset="ClassFile.doc.html#20080">siehe JVM-Spezifikation</a>
            </p>
            <graphic width="500" src="java/cf4.gif" caption="erstes Element des constant pools / Referenz auf Superklasse" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_class</code> die einen Verweis auf auf das zwölfte Element des Konstantenpools (0x0C) enthält. Zum Lesezeitpunkt der ersten Konstante kann diese Referenz noch nicht aufgelöst und auf Gültigkeit geprüft werden. (Später sehen wir, daß es sich um eine Referenz auf <code>java.lang.Object</code> handelt).<br/>
Hierbei handelt es sich immer um die Referenz auf die Superklasse. Auch für die API-Klasse <code>Object</code> selbst findet sich diese Refenz in der Klassendatei, auch wenn Diassemblierungswerkzeuge wie <code>javap</code> diese nicht ausgeben.</p>
            <graphic width="500" src="java/cf5.gif" caption="zweites Element des constant pools / this Referenz" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_class</code> die einen Verweis auf auf das 13. Element des Konstantenpools (0x0D) enthält. An dieser Stelle findet sich der String <code>Act</code>, also der Klassenname der zur Klassendatei gehörigen Klasse selbst. Auch hierbei handelt es sich zunächst um eine nicht auflösbare Vorwärtsreferenz.<br/>
Technisch gesehen realisiert sie den <code>this</code>-Verweis.</p>
            <graphic width="500" src="java/cf6.gif" caption="drittes Element des constant pools / Konstruktoren-Verweis" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_Methodref</code>. Die folgenden zwei Bytes (im Beispiel: 0x00 01) bezeichnen das referenzierte Objekt, gefolgt vom Methodenindex (0x00 04). Im Beispiel handelt es sich um das Objekt mit der Referenznummer 1 (=erstes Element des Konstantenpools, die Superklasse <code>Object</code>). Unter der Referenznummer 0x04 wird auf die Methode <code>&lt;init&gt;()</code> verweisen. Da die betrachtete Klasse <code>Act</code> keinen eigenen Konstruktor definiert, wird der der Superklasse aufgerufen.</p>
            <graphic width="500" src="java/cf7.gif" caption="viertes Element des constant pools / Rückgabetyp des 14. Elements" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_NameAndType</code>. Die folgenden beiden Bytes (0x00 0E) verweisen auf die zu beschreibende Position innerhalb des Konstantenpools (im Beispiel: <code>init</code>). Dieser Position wird der and Position 0x10 spezifizierte Typ als Rückgabetyp zugeordnet -- im Beispiel <code>()V</code>; also <code>void</code>.</p>
            <graphic width="500" src="java/cf8.gif" caption="fünftes Element des constant pools / Konstante Zeichenkette" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_Utf8</code> leitet einen konstenten Zeichenketten-Ausdruck ein.<br/>
Zeichenketten werden generell im Unicode UTF-8 Format abgelegt, wobei jedoch aus Speicherplatzeffizienzgründen für die Zeichen zwischen <code>\u0001</code> und <code>\u007F</code> nur jeweils ein Byte benötigt werden. Für alle anderen Unicode-Symbole wird der entsprechende 2- bzw. 3-Byte Speicherplatz zur Verfügung gestellt.<br/>
Die Konstante wird von der Länge der Zeichenkette (im Beispiel: 13) gefolgt, daher kann auf eine terminierende Null verzichtet werden.<br/>
Die Bedeutung dieser -- im Java-Quellcode nicht enthaltenen -- Zeichenkette wird im Kontext des Klassenladevorgangs deutlich.</p>
            <graphic width="500" src="java/cf9.gif" caption="sechstes Element des constant pools / Methodenname" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_Utf8</code>. Sie leitet den in der Klasse <code>Act</code> spezifizierten Methodennamen <code>doMathForever</code> ein.</p>
            <graphic width="500" src="java/cf10.gif" caption="siebtes Element des constant pools / Zeichenkette Exceptions" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_Utf8</code>, die den fixen String <em>Exceptions</em> einleitet.</p>
            <graphic width="500" src="java/cf11.gif" caption="achtes Element des constant pools / Zeichenkette LineNumberTable" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_Utf8</code>, die den fixen String <em>LineNumberTable</em> einleitet.</p>
            <graphic width="500" src="java/cf12.gif" caption="neuntes Element des constant pools / Zeichenkette SourceFile" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_Utf8</code>, die den fixen String <em>SourceFile</em> einleitet.</p>
            <graphic width="500" src="java/cf13.gif" caption="zehntes Element des constant pools / Zeichenkette LocalVariables" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_Utf8</code>, die den fixen String <em>LocalVariables</em> einleitet.</p>
            <graphic width="500" src="java/cf14.gif" caption="elftes Element des constant pools / Zeichenkette Code" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_Utf8</code>, die den fixen String <em>Code</em> einleitet.</p>
            <graphic width="500" src="java/cf15.gif" caption="zwölftes Element des constant pools / Zeichenkette java.lang.Object" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_Utf8</code>, die den String <em>java/lang/Object</em> einleitet. Vom ersten Element des Konstantenpools referenziertes Element. Die in der Java-Hochsprache üblichen Punkte zur Trennung der Pakte, Subpakete und Klassennamen werden in der JVM konsequent (aus historischen Gründen) durch Querstriche ersetzt.</p>
            <graphic width="500" src="java/cf16.gif" caption="13. Element des constant pools / Zeichenkette Act" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_Utf8</code>, die den String <em>Act</em> einleitet. Vom zweiten Element des Konstantenpools referenziertes Element. Name der Klasse.</p>
            <graphic width="500" src="java/cf17.gif" caption="14. Element des constant pools / Zeichenkette init" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_Utf8</code>, die den String <em>&lt;init&gt;</em> einleitet. Methodenname der innerhalb der Superklasse <code>Object</code>. Der Rückgabewert dieser Methode ist im vierten Element des Konstantenpools abgelegt.</p>
            <graphic width="500" src="java/cf18.gif" caption="15. Element des constant pools / Zeichenkette snipet.java" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_Utf8</code>, die den String <em>snipet.java</em> -- den Namen der Quellcodedatei in der sich die Definition der Klasse <code>Act</code> befindet -- einleitet.</p>
            <graphic width="500" src="java/cf19.gif" caption="16. Element des constant pools / Zeichenkette ()V" center="yes"/>
            <p>Konstante vom Typ <code>CONSTANT_Utf8</code>, die den String <em>()V</em> einleitet. Methodendeskriptor, der weder Übergabeargumente noch Rückgabetyp besitzt.</p>
            <graphic width="500" src="java/cf20.gif" caption="Zugriffsflags" center="yes"/>
            <p>Zugriffsflags für die Klasse <code>Act</code>. Der konkrete Code ergibt sich aus der binären ODER-Verknüpfung verschiedener Zugriffsflaggen, die in untenstehender Tabelle wiedergegeben sind.</p>
            <tabular>
               <head length="3">
                  <column title="Flag"/>
                  <column title="Wert"/>
                  <column title="Beschreibung"/>
               </head>
               <body>
                  <row>
                     <cell>ACC_PUBLIC</cell>
                     <cell>0x0001</cell>
                     <cell>
                        <code>public</code>-Deklaration; Zugriffbar von allen anderen Klassen, auch außerhalb des eigenen Pakets</cell>
                  </row>
                  <row>
                     <cell>ACC_FINAL</cell>
                     <cell>0x0010</cell>
                     <cell>
                        <code>final</code>-Deklaration; Verbot der Vererbung</cell>
                  </row>
                  <row>
                     <cell>ACC_SUPER</cell>
                     <cell>0x0020</cell>
                     <cell>Besondere Behandlung der Superklasseninstruktionen bei Aufruf über Opcode <a href="#invokespecial">
                           <code>invokespecial</code>
                        </a>
                     </cell>
                  </row>
                  <row>
                     <cell>ACC_INTERFACE</cell>
                     <cell>0x0200</cell>
                     <cell>Struktur ist Schnittstelle, keine Klasse</cell>
                  </row>
                  <row>
                     <cell>ACC_ABSTRACT</cell>
                     <cell>0x0400</cell>
                     <cell>Abstrakte Struktur, von der keine Ausprägungen erzeugt werden können</cell>
                  </row>
               </body>
            </tabular>
            <graphic width="500" src="java/cf20a.gif" caption="Referenz auf this und super" center="yes"/>
            <p>Referenz in den Konstantenpool, auf die Klasse selbst (<code>this</code>) und die Superklasse (<code>super</code>).</p>
            <graphic width="500" src="java/cf21.gif" caption="interface_count und fields_count" center="yes"/>
            <p>
               <code>interface_count</code>: Anzahl der durch die Klasse implementierten Schnittstellen.<br/>
               <code>fields_count</code>: Anzahl der Klassen- oder Instanzvariablen der Klasse.</p>
            <graphic width="500" src="java/cf22.gif" caption="methods_count" center="yes"/>
            <p>Anzahl der durch die Klasse implementierten Methoden.<br/>
Die Zahl ergibt sich aus der tatsächlich durch den Anwender definierten Anzahl und den impliziten, d.h. durch den Compiler hinzugefügten (z.B. Konstruktor), Methoden.</p>
            <graphic width="500" src="java/cf23.gif" caption="methods_info" center="yes"/>
            <p>Informationen über die in der Klasse <code>Act</code> definierten Methoden.<br/>
Die Zugriffsflaggen (0x00 09) weisen <code>doMathForever()</code> als <code>static</code> und <code>public</code> aus. (Die konkrete Wertebelegung kann untenstehender Aufstellung entnommen werden. Auch in diesem Falle wird der tatsächliche Wert durch Boole'sche ODER-Verknüpfung der Einzelwerte gebildet.)<br/>
Der Verweis (0x06) auf das sechste Element des Konstantenpools referenziert den Methodennamen im Klartext. Der zweite Verweis (0x10) auf den Konstantenpool kennzeichnet <code>doMathForever()</code> als parameterlose Methode ohne Rückgabetypen.</p>
            <tabular>
               <head length="3">
                  <column title="Flag"/>
                  <column title="Wert"/>
                  <column title="Beschreibung"/>
               </head>
               <body>
                  <row>
                     <cell>ACC_PUBLIC</cell>
                     <cell>0x0001</cell>
                     <cell>
                        <code>public</code>-Deklaration; Zugriffbar von allen anderen Klassen, auch außerhalb des eigenen Pakets</cell>
                  </row>
                  <row>
                     <cell>ACC_PRIVATE</cell>
                     <cell>0x0002</cell>
                     <cell>Als <code>private</code> deklariert, daher nur innerhalb der definierenden Klasse verwendbar</cell>
                  </row>
                  <row>
                     <cell>ACC_PROTECTED</cell>
                     <cell>0x0004</cell>
                     <cell>
                        <code>protected</code>-Deklaration, Zugriff nur in Subklassen möglich</cell>
                  </row>
                  <row>
                     <cell>ACC_STATIC</cell>
                     <cell>0x0008</cell>
                     <cell>
                        <code>static</code>-Deklaration, keine Auswirkungen auf Sichtbarkeit und Zugriffsrechte</cell>
                  </row>
                  <row>
                     <cell>ACC_FINAL</cell>
                     <cell>0x0010</cell>
                     <cell>
                        <code>final</code>-Deklaration; nach initialer Zuweisung keine Wertänderung möglich</cell>
                  </row>
                  <row>
                     <cell>ACC_VOLATILE</cell>
                     <cell>0x0040</cell>
                     <cell>
                        <code>volatile</code>-Deklaration; keine Berücksichtung in Optimierungsmaßnahmen</cell>
                  </row>
                  <row>
                     <cell>ACC_TRANSIENT</cell>
                     <cell>0x0080</cell>
                     <cell>
                        <code>transient</code>-Deklaration; keine Berücksichtung durch Perisistenzmanager</cell>
                  </row>
               </body>
            </tabular>
            <graphic width="500" src="java/cf24.gif" caption="Attribute der Methode doMathForever()" center="yes"/>
            <p>Die Methode <code>doMathForever()</code> verfügt nur über genau ein Attribut, daher ist der <code>attribute count</code> zu Beginn der Bytesequenz auf 0x00 01 gesetzt. Dieses eine Attribut wird durch Index 11 innerhalb des Konstantenpools referenziert. Dort ist die Zeichenkette <code>Code</code> lokalisiert. Dadurch wird angezeigt, daß die folgenden Bytes die Implementierung dieser Methode beinhalten.<br/>
Der abschließende vier-Byte Indikator enthält die Länge der Methodenimplementierung (im Beispiel: 0x30).</p>
            <graphic width="500" src="java/cf25.gif" caption="maxStack und maxLocals der Methode doMathForever()" center="yes"/>
            <p>
               <code>maxStack</code>: Maximalhöhe des Operandenstacks die während der Methodenausführung erreicht werden kann. (Im Beispiel: 2; die Opcode-Implementierung der beiden verwendeten arithmetischen Operationen benötigen niemals mehr als zwei Stackpositionen.)<br/>
               <code>maxLocals</code>: Anzahl der lokalen Variablen. (die verwendete Variable <code>i</code>)</p>
            <graphic width="500" src="java/cf26.gif" caption="Bytecode und Ausnahmentabelle der Methode doMathForever()" center="yes"/>
            <p>Die <code>code length</code> legt die Anzahl der folgenden Bytecode-Instruktionen fest (im Beispiel: 12), darauf folgen die tatsächlichen Opcodes.</p>
            <verbatim>pc    instruction    mnemonic
0     03             iconst_0
1     3B             istore_0
2     840001         iinc 0 1
5     1A             iload_0
6     05             iconst_2
7     68             imul
8     3B             istore_0
9     A7FFF9         goto 2</verbatim>
            <p>Die Ausnahmentabelle (<code>Exception Table</code>) enthält die Anzahl der durch die Methode aufgefangenen Ausnahmeereignisse; im Beispiel: 0.</p>
            <graphic width="500" src="java/cf27.gif" caption="Eigenschaften des Code-Bereichs der Methode doMathForever()" center="yes"/>
            <p>In diesem Bereich werden zusätzliche Charakteristika des bereits definierten Codebereichs hinterlegt, z.B. Debugginginformation.<br/>
Im betrachteten Falle ist nur eine Eigenschaft angegeben (<code>attribute_count</code> = 0x01). Diese referenziert das achte Element des Konstantenpools -- die Zeichenkette LineNumberTable. Die beiden abschließenden Attribute bezeichnen die Länge dieser Tabelle (0x12) und die Anzahl der Einträge (0x4).<br/>
Die LineNumberTable des Beispiels:</p>
            <verbatim>line 4: i = 0;
line 5: while(true) {
line 6: i += 1;
line 7: i *= 2;</verbatim>
            <graphic width="500" src="java/cf28.gif" caption="Zuordnung zwischen LineNumberTable und der Methode doMathForever()" center="yes"/>
            <p>Diese Datenstruktur stellt die Zuordnung zwischen den Quellcodezeilen und den resultierenden Opcodes her.</p>
            <verbatim>
LineNumberTable[0]:  iconst_0    istore_0
LineNumberTable[1]:  iinc 0 1
LineNumberTable[2]:  iload_0     iconst_2    imul  istore_0
LineNumberTable[3]:  goto 2</verbatim>
            <graphic width="500" src="java/cf29.gif" caption="Zugriffsflaggen und Indizes der Klasse Act()" center="yes"/>
            <p>Diese zweite methodenbezogene Struktur gibt Auskunft über den Konstruktor der Klasse <code>Act</code>.<br/>
Im ersten Doppelbyte sind die Zugriffsrechte spezifiziert; in diesem Falle sind keine gesonderten Festlegungen getroffen -- es handelt sich um eine <em>einfache</em> Methode.<br/>
Die Referenz in den Konstantenpool verweist auf die implementierende Methode (im Beispiel: Position 0x0E, dort findet sich die Methode <code>&lt;init&gt;</code>).<br/>
Durch die letzten beiden Bytes wird der Typ des Konstruktors referenziert, im betrachteten Beispiel die Position 0x10 im Konstantenpool, mithin ein parameterloser Konstruktor.</p>
            <graphic width="500" src="java/cf30.gif" caption="Attribute der Klasse Act()" center="yes"/>
            <p>Der Zähler (ersten beiden Bytes) zu beginn der Struktur zeigt an, daß nur ein Attribut der Klasse <code>Act()</code> folgt. Im Beispielfall handelt es sich dabei um das über den Index 11 (0x0B) angesprochene Element des Konstantenpools, die Zeichenkette <code>Code</code>.<br/>
Der abschließend angegebene Längenzähler fixiert die Anzahl der folgenden Bytes.</p>
            <graphic width="500" src="java/cf31.gif" caption="maxStack und maxLocals der Klasse Act()" center="yes"/>
            <p>Analog der Definition für Methoden, die maximale Höhe des Operandenstacks und die Anzahl der lokalen Variablen.</p>
            <graphic width="500" src="java/cf32.gif" caption="Bytecode und Ausnahmetabelle der Klasse Act()" center="yes"/>
            <p>Opcode-Implementierung des Konstruktors, sowie die Aufzählung der durch ihn potentiell ausgelösten Ausnahmeereignisse (im keine, daher Anzahl gleich Null).<br/>
Die Implementierung in Java-Bytecode:</p>
            <verbatim>pc    instruction    mnemonic
0     2A             aload_0
1     B70003         invokeonvirtual #3 &lt;Method java.lang.Object &lt;init&gt; ()V&gt;
4     B1             return</verbatim>
            <graphic width="500" src="java/cf33.gif" caption="Eigenschaften des Code-Bereichs der Klasse Act()" center="yes"/>
            <p>Anzahl der Eigenschaften im ersten Doppelbyte (im Beispiel: 1). Die spezifische Eigenschaft wird durch Index acht im Konstantenpool (=<code>LineNumberTable</code>) näher definiert.<br/>
Diese Tabelle hat die Länge 0x06, mit einem einzigen Eintrag.</p>
            <graphic width="500" src="java/cf34.gif" caption="Zuordnung zwischen LineNumberTable und der Klasse Act()" center="yes"/>
            <p>Zuordnung der Quellcodezeilennummern zu den resultierenden Opcodes.</p>
            <graphic width="500" src="java/cf35.gif" caption="Allgemeine Eigenschaften" center="yes"/>
            <p>Am Ende einer Klassendatei kann eine beliebige Menge allgemeiner Attribute angeben werden.<br/>
für das Beispiel wurde durch den Compiler genau ein Attribut erzeugt, ein Verweis auf die Quelldatei (Konstantenpool-Index 0x09). Auf diese Information folgt ein Verweis auf den Namen der Quellcodedatei (Konstantenpool-Index 0x15).</p>
            <p>
               <b>Schlußbemerkungen</b>:</p>
            <graphic src="java/jvmimpl.gif" caption="Implementationsansätze für die Execution Engine der JVM" center="yes"/>
            <p>
               <small>Graphik aus: <a href="http://www.mathema.de/cache/images/java/jvm1/jvm-teil1.html">Raner, M.: Blick unter die Motorehaube</a>
               </small>
            </p>
            <p>Die interpretative Ausführung einer <code>class</code>-Datei mit der virtuellen Java-Maschine ist jedoch keineswegs zwingend, auch wenn sie das derzeit am häufigsten anzutreffende Vorgehen verkörpert. Bereits in der Standardedition des Java Development Toolkits von SUN wird seit Version 1.2 ein <em>just in time compiler</em> mitgeliefert, der transparent in die Ausführungsumgebung integriert ist. Er durchbricht die befehlweise interpretative Abarbeitung und greift den bei der Abarbeitung dynamisch durch den Interpretationsprozeß entstehenden plattformspezifischen Maschinencode ab und puffert ihn zwischen. Bei jeder erneuten Ausführung derselben Bytecodesequenz wird nun dieser bereits übersetzte Code ausgeführt. Dieses Vorgehen ist in den verbreiteten JVM-Implementierungen der Internet-Browser von Netscape und Microsoft verwirklicht. Ebenso bieten fast alle verfügbaren Java-Entwicklungsumgebungen diese Laufzeit-optimierende Komponente an. Der dadurch erzielte Geschwindigkeitsvorteil bewegt sich, je nach Struktur der Anwendung, zwischen zehn und 50 Prozent.<br/>
Den größten Gewschwindigkeitszuwachs verspricht man sich jedoch von der vollständigen Realisierung der virtuellen Maschine in Hardware; damit wird sie de facto zur realen Maschine. Hierzu liegen jedoch noch keine Ergebnisse vor, welche die der derzeitigen Implementierung auf handelsüblichen Prozessoren signifikant überträfen.<br/>
Eine andere Sichweise nutzt das Bytecodeformat welches eine Zwischenrepräsentation darstellt nicht zur Interpretation mit dem Ziele der direkten Ausführung, sondern als Eingabeformat eines weiteren Übersetzungsschrittes, der üblicherweise plattformabhängigen nativen Code erzeugt. Für C++ existieren bereits Umsetzungen, die Bytecode in übersetzungsfähigen C++-Quellcode transformieren. Eine Spielart hiervon bildet das diskutierte Werkzeug <code>javap</code> dessen Ausgabeformat, nach einigen Umformumgen, direkt als Eingabe weiterer Übersetzer akzeptiert wird.</p>
            <scriptElement type="links" title="Weiterführende Links">
               <link>
                  <a href="http://www.artima.com/insidejvm/resources/">Inside the Java Virtual Machine</a>
               </link>
            </scriptElement>
         </div>
      </region>
      <region numbered="yes">
         <topic name="Betriebssysteme">Betriebssysteme</topic>
         <p>Mit der zunehmenden Verlagerung der Steuerungsaufgaben -- wie Bandwechsel, Auswahl des nächsten zu berechnenden Aufgabe sowie Überwachtung des Maschinenstatus -- eines Rechners weg vom (menschlichen) Operateur hin zu dafür entwickelten Softwaresystemen entstand bereits in der Ära der <a href="#IBM7094">IBM 7094</a> der Begriff des <em>Betriebssystem</em>s für Programme der genannten Funktionalität. (Vgl. <a href="index.html#ceruzzi">[Cer03, S. 105]</a>)</p>
         <subtopic>Ablaufsteuerung</subtopic>
         <p>Eine der zentralen Aufgaben jedes Betriebssystems ist die Organisation und Verwaltung der aus einem Rechnersystem ausgeführten Programme. Die zuständige Betriebssystemkomponente wird daher zumeist mit <em>
               <keyword>Ablaufsteuerung</keyword>
            </em> bezeichnet.<br/>
        Die Ablaufsteuerung organisiert die auszuführenden Aufgaben in Prozessen und organisiert deren Zuordnung zur CPU um Berechnungsergebnisse zu erhalten.</p>
         <subsubtopic>Prozesse und Threads</subsubtopic>
         <p>Aktuelle Rechnersysteme erlauben es verschiedene Aufgaben (scheinbar) zu einem Zeitpunkt auszuführen. So können gleichzeitig Dateien auf die Festplatte geschrieben werden und mit verschiedenen Applikationen (etwa Textverarbeitung, Web-Browser und MP3-Player) gearbeitet werden.</p>
         <p>Voraussetzung dieses Verhaltens ist die Übertragung eines auf einem Speichermedium (Festplatte, CD-ROM, DVD oder Internet-Server) zur Verfügung stehenden Programms in den Hauptspeicher der Maschine und dessen Ausführung durch den (oder die) Prozessor(en).</p>
         <p>Das Betriebssystem betrachtet alle auszuführenden Programme und Aufgaben einheitlich als <em>
               <keyword>Prozeß</keyword>
            </em> (oder <em>
               <keyword>Task</keyword>
            </em>), der über bestimmte festgelegte Eigenschaften verfügt und im selben Schema wie alle anderen Prozesse behandelt wird.</p>
         <p>Gemäß der Anzahl der gleichzeitig verarbeitbaren Prozesse wird zwischen <em>
               <keyword>Single Tasking</keyword>
            </em>-Systemen, welche zu einem gegebenen Zeitpunkt nur genau einen einzigen Prozeß abarbeiten können, und <em>
               <keyword>Multitasking</keyword>
            </em> unterschieden. Letztere setzen durch schnelle Umschaltung zwischen den Einzelprozessen die sog. <em>
               <keyword>Multiprogrammierung</keyword>
            </em> um.</p>
         <p>Solange das ausführende System jedoch nur eine gleichzeitig aktive Verarbeitungseinheit bietet, ist ausschließlichlich <em>
               <keyword>nebenläufig</keyword>e Verarbeitung</em> (auch: <em>
               <keyword>Pseudoparallelität</keyword>
            </em>) realisierbar, welche durch schnelle Prozeßumschaltungen den
        Eindruck der simultanen Abarbeitung verschiedener Prozesse erweckt.<br/>
        Reale <keyword>Parallelität</keyword> ist ausschließlich durch geeignete Hardwareunterstützung, d.h. durch die Bereitstellung duplizierter Funktionseinheiten erzielbar, die zu einem Zeitpunkt mehr als einen Prozeß ausführen.</p>
         <p>
            <b>Prozeßerzeugung</b>
            <br/>
        Zur Erzeugung eines neuen Prozesses müssen die auszuführenden Instruktionen (d.h. das Programm) sowie die zur Programmverarbeitung benötigten Hauptspeicherbereiche (Stack und Heap) verfügbar sein. Programmdaten und darauf operierender Code bilden zusammengenommen den <em>
               <keyword>Prozeßkontext</keyword>
            </em>.<br/>
      Zusätzlich müssen betriebssystemseitig benötigte Verwaltungsdaten zur Kontrolle verschiedener Aspekte der laufenden Prozesse bereitgestellt werden. Dieser Datenbereich wird mit dem Sammelbegriff <em>
               <keyword>Prozeßkontrollblock</keyword>
            </em> oder auch <em>
               <keyword>Prozeßtabelle</keyword>neintrag</em> bezeichnet.</p>
         <p>Jeder Eintrag in der Prozeßtabelle enthält diejenigen Daten, die benötigt werden um einen Prozeß verwalten können. Hierzu zählen insbesondere alle Angaben über den Zustand des Prozesses, die benötigt werden um ihn nach einem Anhalten (etwa durch Taskumschaltung) wieder lauffähig restaurieren zu können.<br/>
        Daher umfaßt der Eintrag in der Prozeßtabelle alle prozessorspezifischen Daten, wie Registerbelegungen sowie den aktuellen Stand des Befehls- und Stackzeigerts. Zusätzlich werden Daten über alle geöffneten Dateien sowie weitere betriebssystemspezifische Verwaltungsdaten (wie Benutzer- und Prozeß-ID) gespeichert.</p>
         <p>Nach <a href="index.html#tanenbaum">[Tan02, S. 95]</a> umfaßt jeder Eintrag der Prozeßtabelle typischerweise die nachfolgend zusammenstellten Eigenschaften.</p>
         <tabular>
            <head length="3">
               <column title="Prozeßverwaltung"/>
               <column title="Speicherverwaltung"/>
               <column title="Dateiverwaltung"/>
            </head>
            <body>
               <row>
                  <cell>Register</cell>
                  <cell>Zeiger auf Textsegment</cell>
                  <cell>Wurzelverzeichnis</cell>
               </row>
               <row>
                  <cell>Befehlszähler</cell>
                  <cell>Zeiger auf Datensegment</cell>
                  <cell>Arbeitsverzeichnis</cell>
               </row>
               <row>
                  <cell>Programmstatuswort</cell>
                  <cell>Zeiger auf Stacksegment</cell>
                  <cell>Dateideskriptor</cell>
               </row>
               <row>
                  <cell>Stackzeiger</cell>
                  <cell/>
                  <cell>Benutzer-ID</cell>
               </row>
               <row>
                  <cell>Prozeßzustand</cell>
                  <cell/>
                  <cell>Gruppen-ID</cell>
               </row>
               <row>
                  <cell>Priorität</cell>
                  <cell/>
                  <cell/>
               </row>
               <row>
                  <cell>Scheduling-Parameter</cell>
                  <cell/>
                  <cell/>
               </row>
               <row>
                  <cell>Prozeß-ID</cell>
                  <cell/>
                  <cell/>
               </row>
               <row>
                  <cell>Elternprozeß</cell>
                  <cell/>
                  <cell/>
               </row>
               <row>
                  <cell>Prozeßfamilie</cell>
                  <cell/>
                  <cell/>
               </row>
               <row>
                  <cell>Signale</cell>
                  <cell/>
                  <cell/>
               </row>
               <row>
                  <cell>Startzeit des Prozesses</cell>
                  <cell/>
                  <cell/>
               </row>
               <row>
                  <cell>Verbrauchte CPU-Zeit</cell>
                  <cell/>
                  <cell/>
               </row>
               <row>
                  <cell>CPU-Zeit der Kinder</cell>
                  <cell/>
                  <cell/>
               </row>
               <row>
                  <cell>Zeitpunkt des nächsten Alarms</cell>
                  <cell/>
                  <cell/>
               </row>
            </body>
         </tabular>
         <p>Zur Erzeugung von Prozessen durch den Anwender stellen die Betriebssysteme entsprechende API-Funktionen zur Verfügung, welche den auszuführenden Code in den Speicher laden und das Betriebssystem zur korrekten Initialisierung des Prozeßkontrollblockes veranlassen.</p>
         <p>UNIX-artige Betriebssysteme wickeln die Prozeßerzegung über die Funktion <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/fork.html" keyword="yes">fork</a> ab. Wird diese in einem Programm aufgerufen, so wird automatisch ein neuer Prozeß -- der <em>
               <keyword>Kindprozeß</keyword>
            </em> -- erzeugt. Dieser wird zunächst als Kopie des aktuell laufenden -- des <em>
               <keyword>Elternprozeß</keyword>
            </em> -- (d.h. desjenigen der <code>fork</code> aufruft) im Speicher angelegt, welche zwar über eigene lokale Variablen, sowie einen eigenen Stack verfügt, aber Zugriff auf dieselben Dateien besitzt wie der Elternprozeß.
   <br/>
   Die Funktion <code>fork</code> regelt dabei über ihren Rückgabewert welche der beiden identischen Kopien als Eltern- und welche als Kindprozeß ausgeführt wird. So wird im Elternprozeß die Prozeßnummer des Kindprozesses zurückgeliefert, während die Funktionskopie des Kindprozesses als Rückgabewert <code>0</code> liefert.<br/>
   Zunächst unterscheiden sich beide Prozeßinstanzen ausschließlich durch die Belegung des Rückgabewertes von <code>fork</code>.</p>
         <scriptElement type="example" name="fork" title="Prozeßerzeugung unter UNIX" filename="createProc.c" resultfile="createProc.out">
            <importText URI="../../../life/vorlesung/sysarch/examples/createProc.c"/>
         </scriptElement>
         <p>Beispiel <scriptRef type="example" name="fork"/> zeigt die Anwendung der Systemfunktion <code>fork</code>.<br/>
    Die lokalen Variablen <code>i</code> und <code>pid</code> stehen nach dem Aufruf von <code>fork</code> sowohl im Eltern- als auch im Kindprozeß zur Verfügung, jedoch verweisen sie auf unterschiedliche Speicherplätze um beiden Prozessen die unabhängige Belegung zu ermöglichen.<br/>
    Insbesondere besitzt <code>pid</code> nach Aufruf und Duplikation der Codebereiche der beiden Prozesse im Elternprozeß den Wert der von <code>0</code> verschiedenen Prozeßnummer des Kindprozesses und setzt daher die Ausführung normal fort.<br/>
    Im Kindprozeß hingegen ist <code>pid</code> mit <code>0</code> belegt und setzt daher mit der Abarbeitung
    in Zeile 11 fort und wird nach Abarbeitung der Schleife die ausschließlich im Elternprozeß ausgeführte Codesequenz der Zeilen 16 bis 22 überspringen.<br/>
    Schlägt die Prozeßerzeugung fehlt, so wird im erzeugenden Prozeß die Prozeßnummer <code>-1</code> zurückgegeben; Ein    Kindprozeß existiert dann naturgemäß nicht.</p>
         <p>Solange der erzeugende Elternprozeß im System existiert, ist jeder Kindprozeß diesem eindeutig zugeordnet. Hierduch entsteht eine hierarchische Struktur aller Prozesse, die sich ausgehend vom Startprozeß <code>init</code> aufspannt.<br/>
    Dieser Startprozeß nimmt eine Sonderrolle im System ein, da er als erster erzeugter Prozeß immer mit der feststehenden Prozeßnummer <code>1</code> versehen ist. Zusätzlich wird er durch die Abwesenheit eines Elternprozesses charakterisiert. Aus diesem Grunde ist <code>init</code> der nicht existente Elternprozeß mit der Prozeßnummer <code>0</code> zugeordnet.</p>
         <p>Terminiert der Elternprozeß im Verlauf der Programmausführung vor dem Kindprozeß, so wird die Elternprozeßnummer im Kind auf die des <code>init</code>-Prozesses gesetzt. Kindprozesse, deren Elternprozeß vor ihnen terminiert, werden als <em>
               <keyword>Waisen</keyword>
            </em> (engl. <em>
               <keyword>Orphan</keyword>
            </em>) bezeichnet, die von <code>init</code>
            <gerquot>adoptiert</gerquot> werden.</p>
         <p>Diese Vorgehensweise wurde gewählt, da der erzeugende Elternprozeß über den Terminierungsstatus des Kindprozesses informiert wird. Dieser wird als <code>int</code>-Wert durch die im Kindprozeß aufgerufene Funktion <code>exit</code> übermittelt. Hierbei gilt unter UNIX die Besonderheit, daß die Binärrepräsentation des tatsächlich zurückgegebenen Wertes durch logisches Und mit <code>377</code> verknüpft wird.</p>
         <p>
            <a name="zombie">Beendet</a> der Kindprozeß seine Ausführung, ohne das der Elternprozeß den Rückgabewert übernimmt, so verbleibt der Kindprozeß als sog. <em>
               <keyword>Zombie</keyword>
            </em> bis zur Terminierung des Elternprozesses im Hauptspeicher.<br/>
    Daher sollte ein erzeugender Prozeß unbedingt <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/wait.html" keyword="yes">wait</a> oder <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/waitpid.html" keyword="yes">waitpid</a> aufrufen um den Terminierungsstatus des Kindprozesses abzufragen und diesem somit die vollständige Terminierung zu ermöglichen.</p>
         <p>Im Windows-System stehen die Standard-API-Funktionen <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/waitforsingleobject.asp" keyword="yes">WaitForSingleObject</a> zum Warten auf das terminieren des erzeugten Kindprozesses bzw. <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getexitcodeprocess.asp" keyword="yes">GetExitCodeProcess</a> zur Abfrage des Rückgabewertes zur Verfügung. Anders als unter UNIX retourniert Windows den numerischen Terminierungsstatus unmodifiziert an den erzeugenden Prozeß.</p>
         <p>Oftmals ist es jedoch nicht gewünscht den vollständigen Code des Kindprozesses auch ungenutzt im Elternprozes zur Verfügung zu stellen, und gleichzeitig umgekehrt im Kindprozess den dort ungenutzen Code des Elternprozesses, den dieser nach der Abspaltung mittels <code>fork</code> ausführt, vorzuhalten.<br/>
    Daher tritt ein Aufruf von <code>fork</code> zumeist in Gesellschaft mit einem Aufruf einer Funktion aus der <code>exec</code>-Familie auf.</p>
         <p>Die Vertreter (typischerweise existieren mindestens fünf spezialisierte Varianten des <code>exec</code>-Aufrufs) dieser Funktionsgruppe ersetzen den gegenwärtig laufenden Prozeß vollständig durch einen anderen. Dessen Code muß zum Aufrufzeitpunkt noch nicht speicherresident sein, sondern kann durch die <code>exec</code>-Funktion nachgeladen werden.<br/>
    Beispiel <scriptRef type="example" name="createProcess2"/> zeigt die Verwendung der Funktion <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/execlp.html" keyword="yes">execlp</a> im Kindprozeß. Dessen Code wird durch den Funktionsaufruf in Zeile 14 vollständig durch den des Beispiels <scriptRef type="example" name="child"/> überlagert.</p>
         <p>Der Überlagerungsprozeß überschreibt den Prozeßkontext vollständig, so daß alle vom Elternprozeß duplizierten Daten und das aktuell ausgeführte Programm danach nicht mehr im Hauptspeicher zugreifbar sind. Aus diesem Grund wird typischerweise nicht der Aufruf <code>fork</code> zur Prozeßerzeugung, sondern <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/vfork.html" keyword="yes">vfork</a> eingesetzt sofern direkt auf den <code>fork</code>-Vorgang ein <code>exec</code>-Aufruf folgt. Die <code>vfork</code>-Funktion besitzt den Vorteil, daß sie keine Duplikation der Datenbereiche des Elternprozesses vornimmt und daher deutlich schneller abgearbeitet werden kann als <code>fork</code>. In der Konsequenz darf der erzeugte Kindprozeß keine Daten verändern, da diese physisch mit dem Elternprozeß geteilt werden.</p>
         <scriptElement type="example" name="createProcess2" title="Prozeßerzeugung und Überlagerung mittels exec unter UNIX" filename="createProc2.c" resultfile="createProc.out">
            <importText URI="../../../life/vorlesung/sysarch/examples/createProc2.c"/>
         </scriptElement>
         <p>Der unabhängig übersetzte Code, welcher durch den Kindprozeß nachgeladen wird ist in Beispiel <scriptRef type="example" name="child"/> dargestellt:</p>
         <scriptElement type="example" name="child" title="Nachgeladener Code des Kindprozesses" filename="child.c">
            <importText URI="../../../life/vorlesung/sysarch/examples/child.c"/>
         </scriptElement>
         <p>Zur Beschleunigung des <code>fork</code>-Aufrufes setzen Linux-Systeme die sog. <em>
               <keyword>Copy-on-Write</keyword>
            </em>-Technik ein. Hierbei werden die für den Kindprozeß bereitzustellenden Datenressourcen nicht direkt bei der Ausführung von <code>fork</code> dupliziert, sondern solange auf die Daten des Elternprozesses lesend zugegriffen, bis der Kind- oder Elternprozeß diese zu verändern wünscht. Erst dann (im Falle des schreibenden Zugriffes) müssen die Daten für den Kindprozeß dupliziert und separat bereitgestellt werden.<br/>
    Hintergrund dieser Optimierungstechnik, die zu deutlichen Geschwindigkeitsgewinnen führen kann, ist die Erkenntnis, daß Kindprozesse nur in seltenen Fällen alle vom Elternprozeß übernommenen Daten verändern. In der überwiegenden Mehrzahl werden die duplizierten Daten hingegen ausschließlich lesend verarbeitet und nur ein kleiner Teil modifiziert.</p>
         <p>Die Windows-Betriebssystemfamilie nimmt die Unterscheidung in Kindprozeßerzeugung und separatem Nachladen des benötigen Codes nicht vor, sondern bündelt beide Vorgänge in der Systemfunktion <a href="http://msdn.microsoft.com/library/en-us/dllproc/base/createprocess.asp" keyword="yes">CreateProcess</a>.<br/>
    Beispiel <scriptRef type="example" name="createProcWin"/> zeigt den Aufruf der genannten Systemfunktion, welche den in Beispiel <scriptRef type="example" name="childWin"/> dargestellten Code als Kindprozeß lädt.</p>
         <scriptElement type="example" name="createProcWin" title="Prozeßerzeugung unter Windows" filename="createProcWin.c" resultfile="createProcWin.out">
            <importText URI="../../../life/vorlesung/sysarch/examples/createProcWin.c"/>
         </scriptElement>
         <scriptElement type="example" name="childWin" title="Quellcode des Kindprozesses" filename="childWin.c">
            <importText URI="../../../life/vorlesung/sysarch/examples/childWin.c"/>
         </scriptElement>
         <p>Die Struktur des Prozeßkontrollblocks (PCB), der auch als <em>Kernel Process Block</em> bezeichnet wird, ist in  <illustrationLink ref="winPcb"/> dargestellt.</p>
         <illustration id="winPcb" width="531" caption="Aufbau des Windows-Prozeßkontrollblocks" gfx="sysarch/winPcb.png"/>
         <p>Grundsätzlich enthält auch der unter Windows benutzte Prozeßkontrollblock die im vorhergehenden dargestellten Eigenschaften. Im Detail (beispielsweise an der Speicherung der geladenen DLL-Bibliotheken) lassen sich jedoch die Plattformbesonderheiten gut erkennen. (Vgl. hierzu auch: <a href="index.html#Solomon">[Sol00, 279 u. 291]</a>)</p>
         <tabular>
            <head length="2">
               <column title="Element"/>
               <column title="Beschreibung"/>
            </head>
            <body>
               <row>
                  <cell>Dispatcher Header</cell>
                  <cell>Verwaltungsinformation der Taskumschaltung</cell>
               </row>
               <row>
                  <cell>Kernel Time</cell>
                  <cell>Verbrauchte priviligierte Rechenzeit</cell>
               </row>
               <row>
                  <cell>User Time</cell>
                  <cell>Verbrauchte Anwenderrechenzeit</cell>
               </row>
               <row>
                  <cell>Processor Affinity</cell>
                  <cell>Zuweisung an genau eine CPU eines Multiprozessorsystems</cell>
               </row>
               <row>
                  <cell>Process Base Priority</cell>
                  <cell>Prozeßpriorität</cell>
               </row>
               <row>
                  <cell>Process State</cell>
                  <cell>Gegenwärtiger Prozeßzustand</cell>
               </row>
               <row>
                  <cell>Process ID</cell>
                  <cell>Eineindeutige Prozeßnummer</cell>
               </row>
               <row>
                  <cell>Parent Process ID</cell>
                  <cell>Prozeßnummer des Elternprozesses</cell>
               </row>
               <row>
                  <cell>Exit status</cell>
                  <cell>Abbruchgrund</cell>
               </row>
               <row>
                  <cell>Create and Exit times</cell>
                  <cell>Erzeugungs- und Terminierungszeitpunkt</cell>
               </row>
               <row>
                  <cell>Next Process Block</cell>
                  <cell>Verweis auf den nächsten Eintrag der Prozeßtabelle</cell>
               </row>
               <row>
                  <cell>Quota Block</cell>
                  <cell>Speichernutzungsbeschränkung</cell>
               </row>
               <row>
                  <cell>Memmory Management Information</cell>
                  <cell>Verschiedene Aussagen über Nutzung des virtuellen Speichers</cell>
               </row>
               <row>
                  <cell>Exception Port</cell>
                  <cell>Kanal der Interprozeßkommunikation.<br/>Prozeßmanager sendet, bei Auftreten eines Ausnahmeereignisses, Nachricht dorthin.</cell>
               </row>
               <row>
                  <cell>Debugger Port</cell>
                  <cell>Kanal der Interprozeßkommunikation.<br/>Prozeßmanager sendet, bei Auftreten eines
                            Debug-Ereignisses, Nachricht dorthin.</cell>
               </row>
               <row>
                  <cell>Device Map</cell>
                  <cell>Zuordnung der logischen Gerätenamen zur jeweiligen Hardware</cell>
               </row>
               <row>
                  <cell>Image Filename</cell>
                  <cell>Name der ausführbaren Binärdatei</cell>
               </row>
               <row>
                  <cell>Image Base Address</cell>
                  <cell>Startadresse der speicherresidenten ausführbaren Binärdatei</cell>
               </row>
               <row>
                  <cell>Module List</cell>
                  <cell>Verzeichnis der geladenen dynamischen Module (DLL-Dateien)</cell>
               </row>
            </body>
         </tabular>
         <p>Die Tabelle zeigt im Kern wesentliche Gemeinsamkeiten mit der Auflistung der Prozeßkontrolfelder des UNIX-Systems auf. So werden auch unter Windows alle im System verwalteten Prozeße einheitlich durch eine numerische Prozeßnummer identifiert. Ebenso besitzt jeder Prozeß (mit Ausnahme des Startprozesses <code>init</code> unter UNIX bzw. <code>Idle</code> unter Windows) einen eindeutigen Elternprozeß.<br/>
Zusätzlich zeigt die Tabelle einige systemspezifische Besonderheiten, wie beispielsweise die Verwaltung der geladenen DLL-Bibliotheksdateien.</p>
         <p>Neben der direkten Möglichkeit Prozesse durch Betriebssystemfunktionen zur erzeugen, bieten hierfür auch Hochsprachenunterstützung an, wenngleich diese im engeren Sinne selbst keine Prozeßerzeugung vornehmen. Typischerweise bieten Hochsprachen lediglich einfach benutzbare Programmierschnittstellen als die nativen des Betriebssystems zur Prozeßerzeugung an. Die Aufrufe dieser Schnittstellen müssen jedoch zur Laufzeit auf die betriebssystemseitig verfügbaren Schnittstellen abgebildet werden. Dies kann bereits zur Übersetzungszeit durch den Compiler, oder zur Laufzeit durch den Interpreter, geschehen.</p>
         <p>Im Falle der Java-Standard-API ist letzterer Ansatz verwirklicht, d.h. die virtuelle Java Maschine interpretiert zur Laufzeit den Hochsprachenaufruf und bildet ihn auf die entsprechende Betriebssystemfunktionalität ab. Innerhalb Javas stellt die Klasse <a fixedType="JDKcurrent" offset="java/lang/Runtime.html" keyword="yes">Runtime</a> verschiedene Varianten einer <code>exec</code>-Funktion zur Verfügung. Ausprägungen der Klasse <code>Runtime</code> fungieren hierbei zur Laufzeit als Schnittstelle zur betriebssystemseitigen Ausführungsumgebung, welche die Java Virtual Machine beherbergt. Daher ist zwar die direkt durch den Programmierer aufgerufene <a fixedType="JDKcurrent" offset="java/lang/Runtime.html#exec(java.lang.String)" keyword="yes">exec</a>-Methode ebenso wie die durch sie aufgerufenen Methoden der Klasse <a fixedType="JDKcurrent" offset="java/lang/ProcessBuilder.html" keyword="yes">ProcessBuilder</a>, welche die betriebssystemseitige Prozeßerzeugung kapselt, in Java realisiert, die Implementierung des <code>ProcessBuilder</code>s durch die nicht als Bestandteil der Standard-API aufgefaßte Klasse <code>ProcessBuilderImpl</code> hingegen als plattformspezifische native Methode vorgenommen.</p>
         <p>Daher verhält sich die durch <code>exec</code>-Javamethode so, wie die Kombination der UNIX-Systemaufrufe <code>fork</code> und <code>exec</code>, da die Javaplattform implizit die Erzeugung eines neuen Prozesses vornimmt und es damit durch <code>exec</code> zu keiner Überlagerung des ausgeführten Programmcodes kommt.<br/>
Ähnlich wie die gleichnamige UNIX-Systemfunktion gestatten Javas <code>exec</code>-Varianten ebenfalls den freien Aufruf externer ausführbarer Dateien, wie <scriptRef type="example" name="JavaExec"/> zeigt.</p>
         <scriptElement type="example" name="JavaExec" title="Prozeßerzeugung unter Java" filename="JavaExec.java" resultfile="JavaExec.out">
            <importText URI="../../../life/vorlesung/sysarch/examples/JavaExec.java"/>
         </scriptElement>
         <p>Der Code zeigt den Aufruf eines externen Programmes, am Beispiel der Erzeugung einer zweiten Java-Virtual-Machine-Instanz welche die Klasse <a href="Child.java" keyword="yes">Child</a> zur Ausführung bringt.<br/>
    Zur Erzeugung einer zusätzlichen Prozeßinstanz muß zunächst mittels der Methode <a fixedType="JDKcurrent" offset="java/lang/Runtime.html#getRuntime()" keyword="yes">getRuntime</a> dasjenige Objekt ermittelt werden, weches die Verbindung zur betriebssystemseitigen Ausführungsumgebung repräsentiert.<br/>
    Die auf Objekten dieses Typs ausführbare Methode <a fixedType="JDKcurrent" offset="java/lang/Runtime.html#exec(java.lang.String[])" keyword="yes">exec</a> gestattet dann die Übergabe einer Kommandozeile an die Betriebssystemumgebung. Im Beispiel wird die Zeichenkette <code>java Child</code> (aufgrund des separiertenden Leerzeichens in zwei <code>String</code>-Objekte aufgespalten) übergeben.<br/>
    Der betriebssystemseitig erzeugte Prozeß wird unmittelbar nach seiner Erzeugung automatisch gestartet und abgearbeitet. Die Java-Methode liefert ein Objekt des Typs <a fixedType="JDKcurrent" offset="java/lang/Process.html" keyword="yes">Process</a> zurück, welches innerhalb der Hochsprache zur Kontrolle des erzeugten Prozesses eingesetzt werden kann.<br/>
    Insbesondere kann auf die Termininierung durch Aufruf der Methode <a fixedType="JDKcurrent" offset="java/lang/Process.html#waitFor()" keyword="yes">waitFor</a> seitens des Erzeugers gewartet werden.</p>
         <p>Als Besonderheit der Java-Plattform besitzen die erzeugten Kindprozesse keinen Zugriff auf die Standardkanäle für Standard-Ein- und -Ausgabe sowie Fehlerausgabe. Stattdessen werden alle Ausgaben des Kindprozesses an den erzeugenden Prozeß umgeleitet, von dem auch alle über die Standardeingabe vermittelten Eingaben erwartet werden.<br/>
    Aus diesem Grunde leitet der Elternprozeß die Ausgabe des Kindprozesses (sie ist Eingabe im erzeugenden Prozeß) mittels <a fixedType="JDKcurrent" offset="java/lang/Process.html#getInputStream()" keyword="yes">getInputStream</a> um und gibt sie anschließend selbst aus.</p>
         <subsubsubtopic>Threads</subsubsubtopic>
         <p>Für viele Aufgaben, welche kurzfristig Nebenläufigkeitstechniken nutzen möchten, stellt der für die Prozeßerzeugung einzuplanende Zeitaufwand eine große Effizienzhürde dar. Insbesondere die Duplizierung des Elternprozeßkontextes nimmt, durch die notwendigen Kopieraufwände zur Bereitstellung der Variableninhalte auch für die Kindprozesse einen großen Zeitaufwand ein.<br/>
        Darüber hinaus ist oftmals -- wie am Beispiel des Aufrufpaares <code>fork</code>-<code>exec</code> bzw. <code>CreateProcess</code> gezeigt -- ausschließlich die Bereitstellung zusätzlicher Ausführungsressourcen gewünscht, ohne die Datenressourcen gleichzeitig zu duplizieren.</p>
         <p>Daher gilt grundsätzlich folgende Aufteilung (vgl. hierzu: <a href="index.html#Tanenbaum">[Tan02, S.98]</a>):</p>
         <tabular>
            <head length="2">
               <column title="Prozeßlokale Elemente"/>
               <column title="Threadlokale Elemente"/>
            </head>
            <body>
               <row>
                  <cell>Adressraum</cell>
                  <cell>Befehlszähler</cell>
               </row>
               <row>
                  <cell>Globale Variablen</cell>
                  <cell>Register</cell>
               </row>
               <row>
                  <cell>Geöffnete Dateien</cell>
                  <cell>Stack</cell>
               </row>
               <row>
                  <cell>Kindprozesse</cell>
                  <cell>Zustand</cell>
               </row>
               <row>
                  <cell>Signale</cell>
               </row>
               <row>
                  <cell>Signalebehandlungsroutinen</cell>
               </row>
               <row>
                  <cell>Abrechnungsdaten</cell>
               </row>
            </body>
         </tabular>
         <p>Aus diesen Gründen haben sich inzwischen separate Ausführungsfäden (sog. <em>
               <keyword>Thread</keyword>s</em>) als <keyword>leichtgewichtige Prozesse</keyword> breit etabliert und den Begriff des <em>
               <keyword>Multithreading</keyword>s</em> in Erweiterung des klassischen Multiprogrammings geprägt.<br/>
        Dieser Prozeßtyp wird innerhalb genau eines Prozeßkontextes zur Ausführung gebracht. Daher kann jeder Thread auf die globalen Variablen des Elternprozesses zugreifen, besitzt jedoch einen eigenen Befehlszähler sowie Speicherplatz für den threadlokalen Stack und seine lokalen Variablen.<br/>
        Durch die Beschränkung der zur Ausführung benötigten Ressourcen auf das absolute Minimum können Threads sehr schnell erzeugt werden und belasten daher die Gesamtleistungsfähigkeit des Systems nur marginal.</p>
         <p>Im UNIX-Betriebssystem Linux steht für C und C++ die <em>POSIX Thread Library</em> (kurz: PThreads) zur Verfügung. Ihre durch den 1995 verabschiedeten Standard IEEE 1003.1c festgelegten Funktionen gestattet es dem Programmierer auf Hochsprachenebene eigenständig Threads zu erzeugen. Beispiel <scriptRef type="example" name="pthreads"/> zeigt die Umsetzung eines Thread-basierten C-Programmes.</p>
         <scriptElement type="example" name="pthreads" title="Threads unter Linux mit PThreads" filename="pthreads.c" resultfile="pthreads.out">
            <importText URI="../../../life/vorlesung/sysarch/examples/pthreads.c"/>
         </scriptElement>
         <p>Die zur Umsetzung des Beispiels genutzte Bibliothek gestattet es, Nebenläufigkeit mit Funktionsgranularität zu realisieren. So wird im Beispiel die Funktion <code>threadedFunction</code> mittels des Aufrufes <a href="http://www2.yo-linux.com/cgi-bin/man.cgi?section=all&amp;topic=pthread_create" keyword="yes">pthread_create</a> als Programmfaden deklariert und ausgeführt.<br/>
    Der Aufruf <a href="http://www2.yo-linux.com/cgi-bin/man.cgi?section=all&amp;topic=pthread_join" keyword="yes">pthread_join</a> sorgt dafür, daß mit der Weiterverarbeitung solange angehalten wird, bis der durch den übergebenen Zeiger identifizierte Thread seine Ausführung beendet hat.<br/>
    Durch Nutzung der global deklarierten Variable <code>counter</code> zeigt der Beispielcode zusätzlich den gemeinsamen Zugriff auf Speicherbereiche durch die beiden erzeugten Threads.</p>
         <p>Der Geschwindigkeitsvergleich zwischen zwei funktional äquivalenten Umsetzungen (<a href="examples/forkBench.c" keyword="yes">forkBench.c</a> und <a href="examples/pthreadBench.c" keyword="yes">pthreadBench.c</a>) zeigt deutlich, die Geschwindigkeitssteigerung beim Einsatz von Threads gegenüber schwergewichtigten herkömmlichen Prozessen.<br/>
    So benötigt die Erzeugung und Terminierung von zehn Prozessen mittels <code>fork</code> 0.3 sec. während die selbe Anzahl Threads in 0.01 sec. angelegt und beendet werden kann. (Meßumgebung: Dual Athlon 1200, Linux 2.6.5)</p>
         <p>Innerhalb der Windows-Betriebssystemumgebung wird zur Threaderzeugung die Standard-API-Funktion <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp" keyword="yes">CreateThread</a> angeboten. Sie operiert, wie der zuvor eingeführte POSIX-Aufruf, ebenfalls auf Funktionsebene. Der Code aus Beispiel <scriptRef type="example" name="threadsWin"/> setzt die aus dem POSIX-Beispiel bekannte Funktionalität unter Nutzung der Windows-API um.</p>
         <scriptElement type="example" name="threadsWin" title="Threads unter Windows mit der Standard-API" filename="threadsWin.c" resultfile="threadsWin.out">
            <importText URI="../../../life/vorlesung/sysarch/examples/threadsWin.c"/>
         </scriptElement>
         <p>Konventionsgemäß kann einer als Thread abzuarbeitenden Funktion in Windows lediglich genau ein Parameter des Typs <code>LPVOID</code> übergeben werden. Ein Verweis auf den erzeugten Thread wird innerhalb der Ausführung der Funktion <code>CreateThread</code> erzeugt und als Adresse an den Aufrufer zurückgeliefert.</p>
         <p>Innerhalb Microsofts .NET-Umgebung vereinfacht sich der Umgang mit Betriebssystem-Threads deutlich. So kapselt, wie in Beispiel <scriptRef type="example" name="netThread"/> dargestellt, die .NET-API durch die Klasse <a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemThreadingThreadPoolMethodsTopic.asp" keyword="yes">ThreadPool</a> die Erzeugung eines Threads vollständig.<br/>
        Die aus der Standard-API bekannte Einschränkung bei der Erzeugung nur höchstens einen Parameter übergeben zu können, ist jedoch auch in der .NET-Umsetzung unverändert präsent. Beispiel <scriptRef type="example" name="netThread"/> setzt die aus den Beispielen <scriptRef type="example" name="pthreads"/> und <scriptRef type="example" name="threadsWin"/> bekannte Funktionalität unter Verwendung des .NET-Frameworks um.</p>
         <scriptElement type="example" name="threadsWin" title="Threads unter Windows mit dem .NET-Framework" filename="netThread.cs" resultfile="netThread.out">
            <importText URI="../../../life/vorlesung/sysarch/examples/netThread.cs"/>
         </scriptElement>
         <p>Ähnlich zum herstellerseitig auf die Windows-Betriebssystemfamilie beschränkte .NET-Framework stellt auch die plattformunabhängig verfügbare Java-Umgebung eine Thread-Unterstützung auf Hochsprachenebene zur Verfügung.<br/>
        Ausgangspunkt der Threadunterstützung ist die Standard-API-Schnittstelle <a fixedType="JDKcurrent" offset="java/lang/Runnable.html" keyword="yes">Runnable</a>.</p>
         <p>Sie definiert die Signatur der Operation <a fixedType="JDKcurrent" offset="java/lang/Runnable.html#run()" keyword="yes">run</a>, welche als Startmethode eines Threads fungiert.</p>
         <p>Anders als die Threadrealisierung durch die POSIX-Bibliothek und die in .NET umgesetzte Unterstützung gestattet Java ausschließlich die Bereitstellung von Nebenläufigkeit auf Klassenebene, da syntaktisch nur diese Schnittstellen implementieren können.<br/>
        Beispiel <scriptRef type="example" name="JavaThreads"/> zeigt die Erzeugung und Ausführung von zwei separaten Threads, welche beide als Ausprägungen der Klasse <code>MyThread</code> realisiert sind.</p>
         <scriptElement type="example" name="JavaThreads" title="Threaderzeugung unter Java" filename="JavaThreadExample.java" resultfile="JavaThreadExample.out">
            <importText URI="../../../life/vorlesung/sysarch/examples/JavaThreadExample.java"/>
         </scriptElement>
         <p>Das Beispiel zeigt die Erzeugung zweiter Threads, welche zunächst als gewöhnliche Java-Objekte vom Typ Klasse, welche <code>Runnable</code> implementiert, bereitgestellt werden.<br/>
    Nach der Objekterzeugung muß die Ausführung je Thread explizit durch Aufruf der Methode <a fixedType="JDKcurrent" offset="java/lang/Thread.html#start()" keyword="yes">start</a> intiiert werden. Erst der Aufruf dieser Methode veranlaßt die virtuelle Java-Maschine dazu die im Thread-Objekt präsente Methode <code>run</code> nebenläufig auszuführen.<br/>
    Würde diese direkt aufgerufen werden, so erfolgt keine nebenläufige, sondern die herkömmliche synchrone, Ausführung.</p>
         <p>Die Ausgabe des Beispiels zeigt gleichzeitig die Grenzen des Threadansatzes auf. Zwar verfügen alle Threads eines Prozeßkontextes über dieselben globalen Variablen, auf die diese unabhängig voneinander lesend und schreibend zugreifen können. Jedoch werden diese Zugriffe prinzipiell unsynchronisiert abgewickelt, wodurch es zu Datenverlust durch Überschreiben vorheriger Ergebnisse kommen kann. Abhilfe schaffen hier die im Abschnitt <em>Konkurrenz und Synchronisation</em> vorgestellten Synchronisationsmechanismen.</p>
         <p>Insgesamt zeigt sich die durch Threads eingeführte Trennung von Ressourcen- und Rechenkapazitätsbündelung als sinnvoll. So kapseln aktuelle Betriebssysteme codeausfürhrende Einheiten generell durch Threads und konzentrieren die Ressorucenverwaltung im umgebenden Prozeß. Daher besitzt sowohl unter Linux, als auch Windows, jeder Prozeß mindestens einen Thread.</p>
         <subsubtopic>Prozessmodi</subsubtopic>
         <p>Zur Umsetzung der Parallelitätsillusion auf Rechnersystemen mit nur einer Berechnungseinheit ist die schnelle Umschaltung zwischen den rechenbereiten und -willigen Threads zwingend notwendig. Da sich je Berechnungseinheit jedoch zu einem Zeitpunkt nur genau ein Thread in Ausführung befinden kann, und die Anzahl der laufenden Rechenvorgänge in einem System typischerweise größer ist als die Anzahl der zur Verfügung stehenden Hardware-Berechnungsressourcen, müssen einzelne Threads temporär von der Ausführung suspendiert werden, um anderen die Berechnung ihrer Ergebnisse zu ermöglichen. Die Selektion eines rechenbereiten Threads und Zuweisung zur Berechhnungseinheit der Hardware obliegt dem sog. <em>
               <keyword>Task Scheduler</keyword>
            </em>.<br/>
        Voraussetzung seiner Arbeit ist die Verwaltung von verschiedenen Threadstatus, die es ermöglichen zwischen rechnenden und von der Berechnung suspendierten Threads zu unterscheiden.</p>
         <p>Im Betriebssystem UNIX werden generell die vier in <illustrationLink ref="procStatusU"/> dargestellten  Threadstatus unterschieden:</p>
         <illustration id="procStatusU" width="600" caption="Threadstatus in UNIX" gfx="sysarch/procStatusUnix.png"/>
         <ul>
            <li>
               <b>warten</b>: Ein Thread in diesem Status ist rechenbereit und ablauffähig. Die zur Verfügung stehenden Rechenenheiten sind jedoch aktuell mit der Verarbeitung anderer Threads beschäftigt; Daher wird der Thread solange im Wartezustand gehalten, bis er einer Recheneinheit zugeteilt wird.</li>
            <li>
               <b>laufen</b>: Ein Thread rechnet aktuell, d.h. er ist genau einer Rechenheit der Hardware zugeteilt und seine Instruktionen werden ausgeführt.</li>
            <li>
               <b>blockiert</b>: Die Ausführung eines Threads wurde unterbrochen weil der Thread auf ein externes Ereignis (z.B. Ein-/Ausgabe) wartet. Dieser Thread kann keiner Recheneinheit zugeteilt werden.</li>
            <li>
               <b>ende</b>: Der Thread hat seine Berechnungsaufgabe abgeschlossen und wird aus dem Hauptspeicher entfernt. Hierbei werden alle ihm zugeteilten Daten- und Speicherbereiche freigegeben.</li>
         </ul>
         <p>Die Zustandsübergänge zwischen den einzelnen Status treten jeweils druch verschiedene Bedingungen und Ereignisse ein.<br/>
        So befindet sich ein neu im System erzeugter Thread zunächst im Zustand <em>wartend</em>, da er nach seiner Erzeugung zunächst auf die erstmalige Zuteilung von Berechnungsressourcen durch das Betriebssystem warten muß. Wird ein Thread zur Verarbeitung selektiert, so wird er genau einer Berechnungseinheit <em>zugeordnet</em> und sein Code dort zur Ausführung gebracht. Hierdurch erfolgt der Zustandsüberganz von <em>wartend</em> zu <em>laufend</em>.<br/>
        Ein Thread verbleibt solange in Ausführung, bis entweder seine zugeteilte Berechnungszeitscheibe abgelaufen ist oder er durch Warten auf ein externes Ereignis (z.B. Bereitstellung von Ein-/Ausgabedaten, Einlagern von Speicherseiten nach Seitenfehler) selbst die Berechnung einstellt. Im Falle des Entzugs der Berechnungssressourcen durch das Betriebssystem nach Ablauf der zugeteilten Rechenzeit geht der (prinzipiell unverändert rechenwillige und -bereite) Thread wieder in den Zustand <em>wartend</em> über und verbleibt dort bis zur erneuten Zuteilung einer Berechnungsressource. Suspendiert der Thread seine Ausführung aufgrund einer externen Wartebedingung vor Ablauf der zugeteilten Zeitscheibe so wird der Thread in den Zustand <em>blockiert</em> überführt. Dort verbleibt er, bis das externe Ereignis eingetreten ist und kann bis dorthin nicht wieder einer Berechnungsressource zugeordnet werden. Das bedeutet, er wird vorübergehend aus der Liste der rechenbereiten Threads (sie befinden sich alle im Zustand <em>wartend</em>) entfernt.<br/>
        Nach dem Ende der Berechnung geht ein Thread in den Zustand <em>beendet</em> über. In diesem Zustand wird sein Ende an seinen zugeordneten Elternprozeß gemeldet und die mit dem Thread verbundenen Daten- und Programmbereiche aus dem Hauptspeicher entfernt. Abschließend werden die zugeordneten Verwaltungsdaten des Betriebssystem und -- sofern es sich um den letzten Thread eines Prozesses handelt -- auch der Prozeßkontrollblock geleert.</p>
         <p>In <illustrationLink ref="procStatusU"/> unberücksichtigt ist der mögliche Zustand <a href="#zombie">
               <em>Zombie</em>
            </a>, der eingenommen wird falls ein Thread zwar seine Ausführung beendet, aber sein Terminieren nicht an den Elternprozeß melden kann.</p>
         <p>Üblicherweise wird in UNIX- und Windows-Betriebssystem der Zustandsübergang von <em>laufend</em> zu <em>wartend</em> automatisch zeitscheibengesteuert durch das Betriebssystem vollzogen (sog. <em>
               <keyword>präemptives Multitasking</keyword>
            </em>). In einigen Systemen (darunter die 16-Bit Windowsvarianten) ist der Prozeß selbst für die Rückgabe der Zeitscheibe und damit Kooperation mit anderen rechenwilligen Prozessen verantwortlich. Daher wird dieser Multitaskingtyp auch als <em>
               <keyword>kooperatives Multitaksing</keyword>
            </em> bezeichnet.<br/>
    Vermöge einer dafür vorgesehenen Betriebssystem-Funktion (bei Windows ist dies der Aufruf <code>yield</code>) muß ein Prozeß die Kontrolle explizit an das Betriebssystem übergeben um anderen Prozessen die Ausführung zu ermöglichen.<br/>
    Durch den Aufruf <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/pause.html" keyword="pause">pause</a> kann ein UNIX-Thread sich selbst von der Ausführung suspendieren, bis er durch ein Signal geweckt wird. Er wird daher nach dem Auruf von <code>pause</code> nicht in den Zustand <code>wartend</code> überführt, sondern verbleibt in <code>blockiert</code> bis er durch ein Signal (=externes Ereignis) geweckt wird.</p>
         <p>Der Code aus Beispiel <scriptRef type="example" name="signal"/> illustriert dies am Beispiel der Wartebedingung auf das Eintreffen des Signals <code>SIGUSR1</code>. Erst wenn dieses durch die Behandlungsroutine <gerquot>
               <code>catcher</code>
            </gerquot> verarbeitet wurde, wird die Ausführung unmittelbar mit der auf die <code>pause</code>-Anweisung folgenden Instruktion fortgesetzt.</p>
         <scriptElement type="example" name="signal" title="Manuelles Suspendieren der Ausführung" filename="pauseEx.c">
            <importText URI="../../../life/vorlesung/sysarch/examples/pauseEx.c"/>
         </scriptElement>
         <p>Die Windows-Systemfamilie bietet in der Version <em>Windows 2000</em> ein dem UNIX-Threadzustandsmodell ähnliches Schema an. (Vgl. hierzu: <a href="index.html#Solomon">[Sol00, S. 384f.]</a>) Es unterscheidet zwischen sieben verschiedenen Status, die ein Thread einnehmen kann. Die zusätzlichen Zustände entstehen durch Aufspaltung UNIX-Zustände <em>wartend</em> und <em>blockiert</em>.<br/>
    Eine Übersicht der verschiedenen Zustände ist in <illustrationLink ref="TStateWin"/> dargestellt.</p>
         <illustration id="TStateWin" width="600" caption="Threadstatus in Windows 2000" gfx="sysarch/procStatusWin.png"/>
         <p>Die einzelnen Zustände sind hierbei:</p>
         <ul>
            <li>
               <b>initialisiert</b> (initialized): Betriebssysteminterner Übergangszustand während der Threaderzeugung.</li>
            <li>
               <b>fertig</b> (ready): Rechenbereite und vollständig speicherresidente Threads. Ausschließlich Threads in diesem Zustand können den Hardwarerecheneinheiten zugeteilt werden.</li>
            <li>
               <b>bereit</b> (standby): Ein in diesem Zustand befindlicher Thread wird der nächsten freiwerdenden CPU zugeordnet. Zu einem Zeitpunkt kann sich nur höchstens ein Thread in diesem Zustand befinden.</li>
            <li>
               <b>rechnend</b> (running): Ein Thread in diesem Zustand ist einer CPU zugeordnet und rechnet.</li>
            <li>
               <b>wartend</b> (waiting): Ein Thread kann durch Eintritt einer Wartebedingung in diesen Zustand versetzt werden. Eine solche Bedingung kann durch Warten auf das Ende einer Ein-/Ausgabeoperation oder durch freiwillige vorzeitige Rückgabe der Zeitscheibe gegeben sein.</li>
            <li>
               <b>übergehend</b> (transition): Ein Thread wird in diesen Zustand überführt, wenn er rechenfertig ist, jedoch threadspezifische Speicherbereiche des Kernels nicht hauptspeicherresident sind.</li>
            <li>
               <b>terminiert</b> (terminated): Sind alle Instruktionen eines Threads ausgeführt, so geht er in diesen Zustand über. Ein Thread muß nach Verlassen dieses Zustands nicht zwingend aus dem Speicher entfernt werden, sondern kann auch neuinitialisiert und erneut ausgeführt werden.</li>
         </ul>
         <p>Auch innerhalb der Virtuellen Java Maschine werden Threads in verschiedenen Ausführungsstatus verwaltet. Im Kern sind die hierbei unterschiedenen Phasen mit <em>erzeugt</em>, <em>lauffähig</em>, <em>blockiert</em> und <em>terminiert</em> stark and die bereits von UNIX bekannten Modi an. Jedoch stehen durch die verschiedenen Java-Methoden zur Threadverwaltung eine Reihe von Eingriffspunkten zur manuellen Beeinflussung der jeweiligen Zustandsübergänge durch den Programmierer zur Verfügung.<br/>
            <illustrationLink ref="JavaThreadStatus"/> zeigt die verschiedenen Zustandsübergänge sowie die Übergangsbedingungen.</p>
         <illustration id="JavaThreadStatus" width="656" caption="Zustandsmodell der Java-Threads" gfx="javaThreads/threadStates.gif"/>
         <subsubtopic>Unterbrechungsverwaltung und Scheduling</subsubtopic>
         <p>Die Rechenbereitschaft und Zuordnung zu einer physischen Ausführungseinheit ist zwar notwendig, jedoch nicht hinreichend, um einem Thread dauerhaften CPU-Zugriff zu ermöglichen. Vielmehr existieren eine Reihe von Gründen, die -- obwohl die zu berechnende Aufgabe noch nicht erfüllt ist -- zum Entzug der CPU-Ressource führen können. In diesem Falle geht der Thread vom Zustand <em>laufend</em> in den Status <em>blockiert</em> über und kann zunächst nicht mehr zur Ausführung gelangen.</p>
         <p>Zusammenfassend werden alle Ereignisse, welche zur Entziehung der CPU-Ressource eines Threads führen als <em>
               <keyword>Unterbrechung</keyword>
            </em> (engl. <em>
               <keyword>Interrupt</keyword>
            </em>) bezeichnet.<br/>
Zusätzlich werden Unterbrechungen hinsichtlich ihrer Ursachen in <em>
               <keyword>synchrone Unterbrechung</keyword>en</em> und <em>
               <keyword>asynchrone Unterbrechungen</keyword>en</em> unterschieden.<br/>
Während synchrone Unterbrechungen innerhalb des ausgeführten Threads selbst durch den Programmcode verursacht werden liegt die Ursache asynchroner Unterbrechungen jenseits des Betriebssystems innerhalb der angeschlossenen Hardware.</p>
         <p>Synchrone Unterbrechungen können sich in einem Instruktionsfluß durch die Struktur des ausgeführten Codes (z.B. Division durch Null) ergeben oder beabsichtigt, durch einen Systemaufruf, ausgelöst worden sein. Bei identischer Konfiguration, d.h. Ausführung desselben Programmes an der selben Speicheradresse unter Rekonstruktion des übrigen Systemzustandes, treten synchrone Unterbrechungen erneut in identischer Weise auf.<br/>
Asynchrone Unterbrechungen ergeben sich aus den dynamischen Zuständen der verwalteten Hardware und können durch Ein-/Ausgabe oder Auftreten des durch einen Hardwarebaustein periodisch generierten Uhrensignals (<a name="#zeitgeber">Zeitgeber</a>) erzeugt worden sein.<br/>
Die nachfolgende Tabelle gibt einen Überblick verschiedener Unterbrechungstypen und ihrer Ursachen.</p>
         <tabular>
            <head length="3">
               <column title="Unterbrechung"/>
               <column title="Typ"/>
               <column title="Auslöser"/>
            </head>
            <body>
               <row>
                  <cell>Ein-/Ausgabeanforderung</cell>
                  <cell>asynchron</cell>
                  <cell>Geräte-Controller</cell>
               </row>
               <row>
                  <cell>Seitenfehler</cell>
                  <cell>synchron</cell>
                  <cell>Betriebssystem</cell>
               </row>
               <row>
                  <cell>Zeitgeber</cell>
                  <cell>asynchron</cell>
                  <cell>Uhrenbaustein</cell>
               </row>
               <row>
                  <cell>Aufruf von Systemfunktionen</cell>
                  <cell>synchron</cell>
                  <cell>Betriebssystem</cell>
               </row>
               <row>
                  <cell>Division durch Null</cell>
                  <cell>synchron</cell>
                  <cell>Betriebssystem</cell>
               </row>
               <row>
                  <cell>Arithmetik Über-/Unterlauf</cell>
                  <cell>synchron</cell>
                  <cell>Betriebssystem</cell>
               </row>
               <row>
                  <cell>Speicherschutzverletzung</cell>
                  <cell>synchron</cell>
                  <cell>Betriebssystem</cell>
               </row>
               <row>
                  <cell>Mausbewegung</cell>
                  <cell>asynchron</cell>
                  <cell>Maus</cell>
               </row>
               <row>
                  <cell>Tastendruck</cell>
                  <cell>asynchron</cell>
                  <cell>Tastatur</cell>
               </row>
               <row>
                  <cell>Netzwerkpaket</cell>
                  <cell>asynchron</cell>
                  <cell>Netzwerkkarte</cell>
               </row>
               <row>
                  <cell>USB</cell>
                  <cell>asynchron</cell>
                  <cell>USB-Controller</cell>
               </row>
               <row>
                  <cell>Stromausfall</cell>
                  <cell>asynchron</cell>
                  <cell>Stromversorgung</cell>
               </row>
            </body>
         </tabular>
         <p>Synchrone Unterbrechungen wie <em>Seitenfehler</em>, <em>Aufruf von Systemfunktionen</em> und die Arithmetikfehler werden zwar durch die ausgeführten Programminstruktionen bedingt, Unterbrechungsauslöser ist jedoch das Betriebssystem selbst.</p>
         <p>Die nähere Analyse der Tabelle zeigt, daß sich die darin aufgelisteten Unterbrechungen nicht nur hinsichtlich ihres Typs, sondern auch graduell im Hinblick auf die anzunehmende Dringlichkeit ihrer Behandlung unterscheiden lassen.<br/>
So werden Unterbrechungen zusätzlich zur getroffenen Einteilung in synchrone und asynchrone noch zusätzlich mit Prioritäten versehen. Beispielsweise kann die Behandlung eines Tastendrucks nicht die Verarbeitung eines Zeitgeberereignisses unterbrechen.<br/>
Zusätzlich zur Priorisierung von Unterbrechungen kann eine Unterbrechung, welche nicht durch andere Unterbrechungen in der Ausführung ihrer Behandlungsroutine unterbrochen werden darf, sich temporär als ununterbrechbar deklarieren um mit Teilen der Behandlung abzuschließen bevor sie durch weitere Unterbrechungen unterbrochen werden kann.<br/>
Im Kern stellt die Ununterbrechbarkeit lediglich eine besondere Form der Priorisierung dar, welche als so hoch einzustufen ist, daß keine anderen Unterbrechungen unterbrechend wirken können.</p>
         <p>Im Falle des Auftretens einer Unterbrechung wird die aktuelle Programmausführung so lange suspendiert, bis die Unterbrechung behandelt wurde. Eine Ausnahme hiervon bilden lediglich niederpriorisierte Unterbrechungen, die versuchen höherpriore zu suspendieren und ununterbrechbare Unterbrechungsbehandlungen.<br/>
            <illustrationLink ref="int"/> zeigt die Behandlung der <code>Unterbrechungsbehandlung<sub>1</sub>
            </code> welches einen Thread des in Ausführung befindlichen <code>Programm</code>es unterbricht. Während der Behandlung der Unterbrechung wird diese ihrerseits durch die <code>Unterbrechungsbehandlung<sub>2</sub>
            </code> unterbrochen und von der Ausführung suspendiert.<br/>
            <code>Unterbrechungsbehandlung<sub>2</sub>
            </code> deklariert sich im Verlauf ihrer Ausführung als Ununterbrechbar. Daher wird das Auftreten der Unterbrechung<sub>3</sub> zunächst solange ignoriert, bis sich die laufende <code>Unterbrechungsbehandlung<sub>2</sub>
            </code> wieder als ununterbrechbar deklariert und durch die <code>Unterbrechungsbehandlung<sub>3</sub>
            </code> unterbrochen wird.<br/>
Nach Abschluß der <code>Unterbrechungsbehandlung<sub>3</sub>
            </code> kehrt diese Routine an diejenige Stelle zurück, in der <code>Unterbrechungsbehandlung<sub>2</sub>
            </code> verlassen wurde und schließt die Behandlung dieser Unterbrechung ab. Nach Ende der <code>Unterbrechungsbehandlung<sub>2</sub>
            </code> kehrt diese zur <code>Unterbrechungsbehandlung<sub>1</sub>
            </code> zurück, welche sie initial unterbrochen hat.<br/>
Ist auch diese Unterbrechungsbehandlung abgeschlossen und wurde nicht zwischenzeitlich durch andere Unterbrechungen unterbrochen, so wird zur Programmausführung zurückgekehrt.</p>
         <illustration id="int" width="600" caption="Unterbrechungsbehandlung" gfx="sysarch/interrupt.png"/>
         <subsubtopic name="scheduling">Scheduling</subsubtopic>
         <p>Zentrale Bedeutung in der Steuerung des Systemverhaltens kommt der <a name="#zeitgeberunterbrechung">Zeitgeberunterbrechung</a> zu. In Betriebssystemen mit präemptivem Multitasking legt sie die technische Basis der Parallelitätssteuerung. Konkret wird jeder zur Ausführung selektierte Thread höchstens für eine feststehende Zeitspanne (die sog. <em>
               <keyword>Zeitscheibe</keyword>
            </em>) ausgeführt, sofern er nicht bereits vor Ablauf der maximalen Rechenzeit blockiert wurde, und nach Ablauf der Zeitscheibe wird ihm die CPU-Ressource entzogen und automatisch dem betriebssysteminternen <em>
               <keyword>Scheduler</keyword>
            </em>-Thread zugeteilet. Dieser während der gesamten Laufzeit des Betriebssystems aktive Thread entscheidet dann welcher Thread aus der Menge der rechenbereiten entnommen und als nächstes der CPU zugeteilt wird.</p>
         <p>Die konkrete Auswahl eines Threads aus der Menge der um Ausführung konkurrierenden erfolgt nach festen Kritierien, die im <em>
               <keyword>Schedulingalgorithmus</keyword>
            </em> hinterlegt sind.<br/>
Grundsätzlich wird in aktuellen Betriebssystemimplementierungen ausschließlich die durch einen Prozeß verursachte CPU-Belastung als Kriterium der Prozessorzuteilug herangezogen und auftretende Ein-/Ausgabeoperationen vernachlässigt. Dieser Einschätzung liegt die Auffassung zu Grunde, daß das Geschwindigkeitsverhalten im wesentlichen durch die zu berechnenden Operationen determiniert wird. Die zunehmend leistungsfähigen Prozessoren offebanren jedoch eine starke Abhängigkeit der Gesamtausführungsgeschwindigkeit von den durchzuführenden Lese- und Schreibzugriffen, da moderne Hauptprozessoren um einen Faktor 10.000 schneller Ergebnisse erzeugen, als sie Festplatten zu liefern vermögen. Daher wird auch das Ein-/Ausgabeverhalten zukünftig in die Zuteilungsstrategie der Threads eingang finden.</p>
         <p>Nachfolgend werden die aktuell präsenten Basisansätze zur Steuerung der Parallelität auf Threadebene vorgestellt und abschließend an Beispielen aus realen Betriebssystemen diskutiert.</p>
         <p>Die Kernfrage der Planung der Threadumschaltung bildet die Fragestellung wann eine Umschaltung zwischen zwei Threads erfolgen soll. Diese Entscheidung kann beim Eintreten verschiedener Ereignisse im System imminent werden:</p>
         <ul>
            <li>Threaderzeugung.<br/>
	Nach der Erzeugung einer neuen rechenfähigen Verwaltungseinheit im Betriebssystem ist zu klären ob diese direkt ausgeführt wird, oder ob der erzeugende Thread zunächst zuende rechnet.</li>
            <li>Threadterminierung.<br/>
	Beendet sich ein aktuell in Ausführung befindlicher Thread oder wird er durch ein externes Ereignis terminiert, so ist ein neuer rechenwilliger Thread zur Ausführung zu selektieren. Liegt ein solcher nicht vor, so wird dem Leerlaufthread (<em>idle</em>-Thread) die CPU zugeteilt.</li>
            <li>Threadblockade.<br/>
	Wird ein Thread aufgrund einer Unterbrechung blockiert, so muß seine Ausführung suspendiert werden, bis die Unterbrechung behandelt wurde.</li>
            <li>Ende einer Unterbrechungsbehandlung.<br/>
	Ist die Behandlung einer Unterbrechung, die zur Blockade eines rechnenden Threads geführt hat, abgeschlossen, so ist der blockierte Thread wieder der Menge der rechenbereiten und -willigen zuzuordnen.</li>
            <li>Zeitgeberereignis.<br/>
	Unterbrechung des aktuell laufenden Threads und Selektion eines rechenbereiten zur Ausführung.</li>
         </ul>
         <p>Prinzipiell sollte sich die Auswahl eines geeigneten Schedulingalgorithmus an der Natur der Ausführungsumgebung orientieren. So muß der Theadumschaltung in batch-orientierten Umgebungen deutlich weniger Aufmerksamkeit zu Teil werden, als für hoch interaktive Systeme, da das Toleranzverhalten der wartenden Anwender bei Stapelverarbeitung deutlich ausgeprägter erscheint. Ebenso bedingen Echtzeitsysteme, welche in fixierten Zeitintervallen die Lieferung einer Antwort garantieren müssen deutlich stärkere Restriktionen an die Auswahl des nächsten rechenbereiten Prozesses als interaktive Workstation- oder Desktopsysteme.<br/>
Einen Überblick der spezifischen Zielsetzungen liefert die nachfolgende Zusammenstellung (vgl. <a href="index.html#tanenbaum">[Tan02, S. 153]</a>):</p>
         <ul>
            <li>Generell:
		<ul>
                  <li>Fairness -- Jeder Thread erhält Rechenzeit</li>
                  <li>Offensichtlichkeit -- Vergabekritierien für Rechenzeit sind offengelegt und nachvollziehbar</li>
                  <li>Balance -- Alle Teile des Systems sind annähernd gleichmäßig ausgelastet</li>
               </ul>
            </li>
            <li>Batch-Systeme:
		<ul>
                  <li>Durchsatz -- Maximiere Auslastung der verfügbaren Ressourcen</li>
                  <li>Durchlaufzeit -- Minimiere Durchlaufzeit jedes Einzeljobs</li>
                  <li>CPU-Belastung -- Maximiere Auslastung der CPU</li>
               </ul>
            </li>
            <li>Interaktive Systeme:
		<ul>
                  <li>Antwortzeit -- Minimiere Antwortzeit für Benutzeranfragen</li>
               </ul>
            </li>
            <li>
               <a fixedType="Wikipedia.de" offset="Echtzeit">Echtzeit</a>systeme:
		<ul>
                  <li>Vorhersagbarkeit -- Garantie des Eintreffens einer Bedingung (z.B. Beendigung einer Berechungsaufgabe) zu einem fixierten Zeitpunkt</li>
               </ul>
            </li>
         </ul>
         <p>In Batch-Systemen wird die Jobverarbeitung im ununterbrechbaren Modus angeboten, d.h. rechenwillige Jobs können bereits rechnende nicht präemptiv unterbrechen. Daher obliegt dem Scheduling Algorithmus <gerquot>lediglich</gerquot> die Auswahl des nächsten auszuführenden Jobs aus der Warteschlange der rechenbereiten nach Beendigung der aktuell verarbeiteten Aufgabe.</p>
         <p>
            <b>
               <keyword>First-Come First Served</keyword>
            </b>: Einfachster Algorithmus, der Jobs in der Reihenfolge ihres Eintritts in die Warteschlange zur Verarbeitung selektiert. Wird ein Job während seiner Ausführung blockiert, so wird er am Ende der Warteschlange eingereiht und muß auf die erneute Zuteilung der CPU warten bis alle vor ihm befindlichen Jobs zugeteilt worden sind.<br/>
Dieser, grundsätzlich auf andere Systemtypen übertragbare, Zuteilungsalgorithmus läßt sich mit relativ wenig Aufwand implementieren und ausführen. Augenscheinlich erfüllt die Einordnung am Warteschlangende auch die gestellten Kriterien der Fairness und Offenheit. Allerdings birgt die Vorgehensweise auch einen gravierenden Nachteil in sich. So benachteiligt die First-Come First-Served-Vorgehensweise Ein-/Ausgabe-intensive Prozesse tendenziell, da diese nach jeder Blockierung am Ende der Warteschlange eingereiht werden. Die hierdurch eintretende Wartezeit verlängert sich zusätzlich proportional zur Systemlast, die direkt mit der Warteschlangenlänge korreliert ist.<br/>
Beispiel <scriptRef type="example" name="sched1"/> zeigt ein Beispiel für die Zuteilungsstrategie nach dem First-Come-First-Served-Prinzip.</p>
         <scriptElement type="example" name="sched1" title="Job-Scheduling nach dem First-Come-First-Served-Prinzip">
            <p>Gegeben seien die Aufgaben <code>j<sub>1</sub>
               </code>, <code>j<sub>2</sub>
               </code> und <code>j<sub>3</sub>
               </code> mit den individuellen Laufzeiten<br/>
               <code>
                  <em>l</em>
               </code>: <code>l(j<sub>1</sub>)=3</code>, <code>l(j<sub>2</sub>)=1</code> und <code>l(<sub>3</sub>)=2</code>.<br/>
Bei Zuteilung nach dem First-Come-First-Served-Prinzip ergeben sich daher als Wartezeiten <code>
                  <em>w(j<sub>i</sub>)</em>
               </code>:<br/>
               <code>w(j<sub>1</sub>)=3</code>
               <br/>
               <code>w(j<sub>2</sub>)=w(j<sub>1</sub>)+1=3+1=4</code>
               <br/>
               <code>w(j<sub>3</sub>)=w(j<sub>2</sub>)+2=w(j<sub>1</sub>)+1+2=3+1+2=6</code>
               <br/>
Daraus ergibt sich die mittlere Wartezeit pro Job als<br/>
               <code>(3+4+6)/3=4<sup>1</sup>/<sub>3</sub>
               </code>.
</p>
         </scriptElement>
         <p>
            <b>
               <a name="SJF">
                  <keyword>Shortest Job First</keyword>
               </a>
            </b>: Diese Zuteilungsstrategie setzt voraus, daß die Laufzeit einer Aufgabe im Voraus bekannt ist und alle Jobs gleichzeitig vorliegen und sich die Menge der zu verarbeitenden Aufgaben während der Verarbeitung nicht ändert. Ist dies der Fall, so werden die Job in der aufsteigenden Reihenfolge ihrer Ausführungszeiten zur Ausführung selektiert. Diese Scheduling-Strategie liefert zuverlässig optimale Ergebnisse, ist jedoch aufgrund der Eingang aufgestellten Restriktionen nur schwer unzusetzen, da in der Praxis häufig auch während der Ausführung noch weitere Jobs hinzukommen, die bei der nächsten Zuteilungsrunde berücksichtigt werden müssen. Insbesondere kann die Ankunft eines <gerquot>Kurzläufers</gerquot>, d.h. Jobs mit kurzer Laufzeit, die Modifikation einer bereits erstellten Zuteilungsreihenfolge bedingen. Überdies ist die Laufzeit von Jobs vor ihrer Ausführung nur schwer zu bestimmen, da beispielsweise die Dauer von Ein-/Ausgabeoperationen nicht im allgemeinen Falle bestimmt werden kann.<br/>
Beispiel <scriptRef type="example" name="sched2"/> zeigt ein Beispiel für die Zuteilungsstrategie nach dem Shortest-Job-First-Prinzip sowie die möglichen anderen Zuteilungsstrategien.</p>
         <scriptElement type="example" name="sched2" title="Job-Scheduling nach dem Shortest-Job-First-Prinzip">
            <p>Gegeben seien die Aufgaben und Laufzeiten aus Beispiel <scriptRef type="example" name="sched1"/>.
Bei Zuteilung nach dem Shortest-Job-First-Prinzip ergibt sich daher die <br/>
Durchlaufreihenfolge <code>s<sub>1</sub>={j<sub>2</sub>, j<sub>3</sub>, j<sub>1</sub>}</code>.<br/>
Die Wartezeiten <code>
                  <em>w</em>
               </code> für jeden Job bei dieser<br/>
Durchlaufreihenfolge ergeben sich als:<br/>
               <code>w(j<sub>1</sub>)=w(j<sub>3</sub>)+3=w(j<sub>2</sub>)+2+3=1+2+3=6<br/>
w(j<sub>2</sub>)=1<br/>
w(j<sub>3</sub>)=w(j<sub>2</sub>)+2=1+2=3</code>
               <br/>
Die mittlere Durchlaufzeit pro Job bei Anwendung der Abarbeitungsreihenfolge<br/>
               <code>s<sub>1</sub>
               </code> liegt daher bei <code>(1+2+3)/3=3<sup>1</sup>/<sub>3</sub>
               </code>.<br/>
               <br/>

Bei der Alternativzuteilung nach dem First-Come-First-Served-Prinzip ergibt sich die in Beispiel
<scriptRef type="example" name="sched1"/> berechnete mittlere Durchlaufzeit
als <code>(3+4+6)/3=4<sup>1</sup>/<sub>3</sub>
               </code>.<br/>
               <br/>

Bei Wahl der Abarbeitungsreihenfolge <code>s<sub>3</sub>={j<sub>1</sub>, j<sub>3</sub>, j<sub>2</sub>}</code>
               <br/>
(dies entspricht der Zuteilungsstrategie <em>Longest-Job-First</em>) ergeben sich die individuellen Wartezeiten als<br/>
               <code>
                  <b>s<sub>3</sub>={j<sub>1</sub>, j<sub>3</sub>, j<sub>2</sub>}</b>:<br/>
w(j<sub>1</sub>)=3<br/>
w(j<sub>2</sub>)=w(j<sub>3</sub>)+1=w(j<sub>1</sub>)+2+1=3+2+1=6<br/>
w(j<sub>3</sub>)=w(j<sub>1</sub>)+2=5</code>
               <br/>
Die mittlere Durchlaufzeit pro Job bei Anwendung der Abarbeitungsreihenfolge<br/>
               <code>s<sub>3</sub>
               </code> liegt daher bei <code>(6+5+3)/3=4<sup>2</sup>/<sub>3</sub>
               </code>.<br/>
               <br/>

Bei Wahl der Abarbeitungsreihenfolge <code>j<sub>2</sub>, j<sub>1</sub>, j<sub>3</sub>
               </code> ergeben sich die individuellen Wartezeiten als:<br/>
               <code>
                  <b>s<sub>4</sub>={j<sub>2</sub>, j<sub>1</sub>, j<sub>3</sub>}</b>:<br/>
w(j<sub>1</sub>)=w(j<sub>2</sub>)+3=1+3=4<br/>
w(j<sub>2</sub>)=1<br/>
w(j<sub>3</sub>)=w(j<sub>1</sub>)+2=w(j<sub>2</sub>)+3+2=1+3+2=6</code>
               <br/>
Die mittlere Durchlaufzeit pro Job bei Anwendung der Abarbeitungsreihenfolge<br/>
               <code>s<sub>4</sub>
               </code> liegt daher bei <code>(4+1+6)/3=3<sup>1</sup>/<sub>3</sub>
               </code>.<br/>
               <br/>

Bei Wahl der Abarbeitungsreihenfolge <code>j<sub>3</sub>, j<sub>1</sub>, j<sub>2</sub>
               </code> ergeben sich die individuellen Wartezeiten als:<br/>
               <code>
                  <b>s<sub>5</sub>={j<sub>3</sub>, j<sub>1</sub>, j<sub>2</sub>}</b>:<br/>
w(j<sub>1</sub>)=w(j<sub>3</sub>)+3=2+3=5<br/>
w(j<sub>2</sub>)=w(j<sub>1</sub>)+1=w(j<sub>3</sub>)+3+1=6<br/>
w(j<sub>3</sub>)=2</code>
               <br/>
Die mittlere Durchlaufzeit pro Job bei Anwendung der Abarbeitungsreihenfolge<br/>
               <code>s<sub>5</sub>
               </code> liegt daher bei <code>(5+6+2)/3=4<sup>1</sup>/<sub>3</sub>
               </code>.<br/>
               <br/>

Bei Wahl der Abarbeitungsreihenfolge <code>j<sub>3</sub>, j<sub>2</sub>, j<sub>1</sub>
               </code> ergeben sich die individuellen Wartezeiten als:<br/>
               <code>
                  <b>s<sub>6</sub>={j<sub>3</sub>, j<sub>2</sub>, j<sub>1</sub>}</b>:<br/>
w(j<sub>1</sub>)=w(j<sub>2</sub>)+3=w(j<sub>3</sub>)+1+3=2+1+3=6<br/>
w(j<sub>2</sub>)=w(j<sub>3</sub>)+1=2+1=3<br/>
w(j<sub>3</sub>)=2</code>
               <br/>
Die mittlere Durchlaufzeit pro Job bei Anwendung der Abarbeitungsreihenfolge<br/>
               <code>s<sub>5</sub>
               </code> liegt daher bei <code>(6+3+2)/3=3<sup>1</sup>/<sub>3</sub>
               </code>.</p>
         </scriptElement>
         <p>Beispiel <scriptRef type="example" name="sched2"/> zeigt, daß die Zuteilungsstrategie nach dem Shortest-Job-First-Prinzip immer ein optimales Ergebnis liefert, das die Wartezeit je Job verkürzt. Neben der durch die vorgestellte Strategie gefundenen Abarbeitungsreihenfolge können jedoch noch weitere existieren, welche dasselbe Optimum erreichen (im Beispiel sind dies <code>s<sub>4</sub>
            </code> und <code>s<sub>6</sub>
            </code>), jedoch keine Alternativreihenfolge, welche das durch Bevorzugung des kürzestlaufenden Jobs ermittelte Optimum unterbieten würde.</p>
         <p>Durch Modifikation des Shortest-Job-First-Prinzips zum <b>
               <keyword>Shortest Remaining Job Next</keyword>
            </b> läßt sich eine der beiden zentralen Einschränkungen des Shortest-Job-First-Algorithmus aufheben. Zwar erfordert auch die modifizierte Variante unverändert Kenntnis über die Laufzeit eines Jobs, jedoch wird der Zuteilungsvorgang nicht mehr nur genau einmal für eine Menge von Jobs ausgeführt, sondern die Zuteilung bei Ankunft eines neuen Jobs dynamisch neu vorgenommen.<br/>
Der Zuteilungsalgorithmus unterscheidet sich daher nur unwesentlich vom Shortest-Job-First-Prinzip und legt den nächsten zu verarbeiten Job bei Ankunft eines neuen neu fest. So können neuankommende Aufgaben bereits bestehende verdrängen, sofern sie eine Gesamtlaufzeit aufweisen, die kürzer als die Restlaufzeit des aktuell verarbeiteten Jobs ist.<br/>
Die Abarbeitungszeit des unterbrochenen Jobs verängert sich dabei um die Dauer des <gerquot>zwischengeschalteten</gerquot> Jobs, der ihn unterbrach.<br/>
Die Shortest-Remaining-Job-Strategie erweist sich als besonders Fair, was die Abarbeitung von (eigentlich bevorzugt zu verarbeitenden) kurzlaufenden Aufgaben betrifft und beseitigt deren -- durch verspätete Ankunft hervorgerufene -- Benachteiligung im Shortest-Job-First-Prinzip.<br/>
            <illustrationLink ref="SRJ"/> zeigt die Unterbrechung des aus den vorhergehenden Beispielen bekannten Jobs <code>j<sub>3</sub>
            </code> nach einer Zeiteinheit durch den neuankommenden Job <code>j<sub>4</sub>
            </code> der Dauer 1.</p>
         <illustration id="SRJ" width="500" gfx="sysarch/srjn.png" caption="Shortest-Remaining-Job-Next-Zuordnung"/>
         <p>Während alle bisher disktutierten Verfahren ausschließlich auf den Stapelverarbeitungsbetrieb zugeschnitten sind, läßt sich die <em>Shortest-Remaining-Job-Next</em>-Zuteilungsstrategie sowohl in Batch-orientierten als auch interaktiven Systemen einsetzen. Allerdings haben sich im Laufe der Zeit eine Reihe spezialisierter Zuteilungsalgorithmen für den Typus multitaskingfähiger interaktiver Systeme herausgebildet, die deren besondere Gegebenheiten besser berücksichtigen. Einige ausgewählte Basistechniken werden nachfolgend eingeführt.</p>
         <p>Das älteste und daher in der Praxis auch am weitesten verbreitete Schedulingverfahren interaktiver Systeme ist unter dem Namen <em>
               <a fixedType="Wikipedia.de" offset="Round_Robin">
                  <keyword>Round Robin</keyword>
               </a>
            </em> geläufig.<br/>
Basisprinzip des Round-Robin-Verfahrens ist die Zuweisung eines fixierten Ausführungsquantums -- der <em>Zeitscheibe</em> -- an jeden Thread. Für die durch das Quantum festgelegte Zeitscheibe erhält jeder Thread exklusiv die CPU und wird nach Ablauf der zugeteilten Zeitscheibe durch den Scheduler unterbrochen, sofern er nicht zuvor durch eine Unterbrechung blockiert wurde.<br/>
Nach Entzug der CPU wird der Thread in eine Wartschlange eingereiht und der nächst in der Schlange befindliche Thread erhält die CPU.<br/>
Round-Robin-basierte Prozessorzuteilung setzt keinerlei Kenntnisse über die Laufzeit eines Threads voraus und kann daher leicht implementiert werden. Die technische Umsetzung erfordert lediglich die Verwaltung einer Liste der Länge der maximal verwaltbaren Threadanzahl.<br/>
Wichtigster Freiheitsgrad des Round-Robin-Verfahrens ist die Länge des CPU-Quantums, welches einem Thread zugeteilt wird. Aufgrund des zu kalkulierenden Zeitaufwandes für die Threadumschaltung (<keyword>Kontextwechsel</keyword>) sollte die Zeitscheibe nicht zu gering festgelegt werden, um das Verhältnis zwischen Rechen- und Verwaltungszeit positiv zu halten. Gleichzeitig sollte die Zeitscheibe nicht zu großen Umfang annehmen, da dies die Interaktivität (d.h. die Wartezeit eines Threads auf CPU-Zutteilung) negativ beeinträchtigt.</p>
         <p>Wird die Laufzeit <code>l</code> mit <code>l(t<sub>1</sub>)=4</code>, <code>l(t<sub>2</sub>)=1</code> und <code>l(t<sub>3</sub>)=2</code> angenommen sowie eine Zeitscheibengröße von genau einer Zeiteinheit fesgelegt, so ergibt sich der in Beispiel <scriptRef type="example" name="RR"/> dargestellte Ablauf.</p>
         <scriptElement type="example" name="RR" title="Round-Robin-Scheduling">
            <ol>
               <li>Rechnend: <code>t<sub>1</sub>
                  </code>
                  <br/>
Warteschlange: <code>{t<sub>2</sub>, t<sub>3</sub>}</code>
               </li>
               <li>Rechnend: <code>t<sub>2</sub>
                  </code>
                  <br/>
Warteschlange: <code>{t<sub>3</sub>, t<sub>1</sub>}</code>
               </li>
               <li>Rechnend: <code>t<sub>3</sub>
                  </code>
                  <br/>
Warteschlange: <code>{t<sub>1</sub>}</code>
                  <br/>
Anmerkung: <code>t<sub>2</sub>
                  </code> hat zu Ende gerechnet.</li>
               <li>Rechnend: <code>t<sub>1</sub>
                  </code>
                  <br/>
Warteschlange: <code>{t<sub>3</sub>}</code>
               </li>
               <li>Rechnend: <code>t<sub>3</sub>
                  </code>
                  <br/>
Warteschlange: <code>{t<sub>1</sub>}</code>
                  <br/>
Anmerkung: <code>t<sub>3</sub>
                  </code> hat zu Ende gerechnet.</li>
               <li>Rechnend: <code>t<sub>1</sub>
                  </code>
                  <br/>
Warteschlange: <code>{}</code>
               </li>
               <li>Rechnend: <code>t<sub>1</sub>
                  </code>
                  <br/>
Warteschlange: <code>{}</code>
                  <br/>
Anmerkung: <code>t<sub>1</sub>
                  </code> hat zu Ende gerechnet.</li>
            </ol>
         </scriptElement>
         <p>Das Beispiel illustriert die Gleichbehandlung aller im System aktiven Threads als weitere zentrale Eigenschaft des Round-Robin-Ansatzes. Dieses Verhalten ist oftmals nicht gewünscht. So sollten Threads, die wichtige Systemereignisse verarbeiten häufiger zugeordnet werden als gewöhnliche Anwenderthreads.
Daher läßt sich das vorgestellte Verfahren durch die Zuordnung von Prioritäten zu jedem Thread dahingehend qualitativ verbessern, daß einzelne Threads bevorzugt zugeordnet werden.<br/>
Die Warteschlangenverarbeitung des Round-Robin-Algorithmus wird als Konsequenz von einer reinen Sortierung gemäß der Erzeugungsreihenfolge auf eine prioritätsbasierte Reihung umgestellt. Der Zuteilungsvorgang wählt unverändert das erste Element der Warteschlange aus und ordnet ihm die CPU-Ressource für den durch die Zeitscheibe vorgegebenen Zeitraum zu.</p>
         <p>Um das <gerquot>Verhungern</gerquot> niederpriorer Threads -- sie würden permanent hinter höherprioren eingeordnet und erst nach deren Ende in der CPU-Verteilung berücksichtigt werden -- zu verhindern werden in der Praxis die Threadprioritäten dynamisch berechnet. Daher wird die <em>
               <keyword>dynamische Priorität</keyword>
            </em> des aktuell ausgeführten Prozesses nach dem Entzug der CPU, in Abhängigkeit seiner statischen Basispriorität, neu festgelegt.<br/>
Beispiel <scriptRef type="example" name="pRR"/> zeigt die prioritätsbasierte Zuordnungsreihenfolge dreier Threads.</p>
         <scriptElement type="example" name="pRR" title="Prioritätsbasiertes Round-Robin-Scheduling">
            <p>Gegeben seien drei mit Prioritätsstufen versehene Threads,<br/>
so daß gelte: <code>p(t<sub>1</sub>)=3</code>, <code>p(t<sub>2</sub>)=1</code> und <code>p(t<sub>3</sub>)=2</code>.<br/>
Die CPU-Zuteilung erfolge dynamisch prioritäsgesteuert.<br/>
Initial sei jeder Thread mit einer dynamischen Priorität von 10 versehen, von der die definierte Prioritätsstufe abgezogen wird. Dem Thread mit der numerisch höchsten Priorität wird anschließend die CPU zugeteilt. Nach Ablauf der Zeitscheibe oder Blockierung des Threads wird die dynamische Priorität um die definierte Prioritätsstufe vermindert.<br/>
Stehen im System mehrere Threads gleicher dynamischer Priorität zur Verfügung,<br/>
so wird bevorzugt einer ausgewählt, der noch nicht ausgeführt wurde. Steht kein Thread höherer dynamischer Priorität zur Verfügung, so wird der Thread, dem aktuell die CPU zugeteilt ist, weiter ausgeführt.<br/>
Nach einmaliger Zuteilung aller Threads beginnt das Verfahren von neuem.</p>
            <ol>
               <li>Rechnend: <code>t<sub>2</sub>
                  </code> (dynamische Priorität: 10-1=9)<br/>
Wartend: <code>t<sub>1</sub>
                  </code> (dynamische Priorität: 10-3=7; noch nie ausgeführt), <code>t<sub>3</sub>
                  </code> (dynamische Priorität: 10-2=8; noch nie ausgeführt)</li>
               <li>Rechnend: <code>t<sub>2</sub>
                  </code> (dynamische Priorität: 9-1=8<br/>
Wartend: <code>t<sub>1</sub>
                  </code> (dynamische Priorität: 7; noch nie ausgeführt), <code>t<sub>3</sub>
                  </code> (dynamische Priorität: 8; noch nie ausgeführt)<br/>
Anmerkung: Verminderung der dynamischen Priorität des ausgeführten Threads, dynamische Priorität der wartenden Threads unverändert.</li>
               <li>Rechnend: <code>t<sub>3</sub>
                  </code> (dynamische Priorität: 8)<br/>
Wartend: <code>t<sub>1</sub>
                  </code> (dynamische Priorität: 7), <code>t<sub>2</sub>
                  </code> (dynamische Priorität: 8-1=7)<br/>
Anmerkung: <code>t<sub>2</sub>
                  </code> bei Kontextwechsel verdrängt, da <code>t<sub>3</sub>
                  </code> höhere dynamische Priorität besitzt.</li>
               <li>Rechnend: <code>t<sub>1</sub>
                  </code> (dynamische Priorität: 7)<br/>
Wartend: <code>t<sub>2</sub>
                  </code> (dynamische Priorität: 7), <code>t<sub>3</sub>
                  </code> (dynamische Priorität: 6)<br/>
Anmerkung: <code>t<sub>1</sub>
                  </code> verdrängt <code>t<sub>3</sub>
                  </code> trotz <gerquot>nur</gerquot> gleicher dynamischer Priorität, da <code>t<sub>1</sub>
                  </code> noch nie ausgeführt wurde.<br/>
Nach dieser Zuteilung beginnt das Verfahren von neuem, da alle Threads einmal zugeordnet wurden.</li>
            </ol>
         </scriptElement>
         <p>Zur vereinfachten Handhabung bieten die Implementierungen des Round-Robin-Verfahrens typischerweise gestufte Prioritätsklassen an, in die einzelne Threads eingeordnet werden. Windows 2000 bietet beispielsweise 32 verschiedene Prioritätsstufen an, von denen 16 (Stufen 16-31) Echtzeitthreads, 15 (Stufen 1-15) Anwenderthreads und genau eine (Stufe 0) dem Leerlaufprozeß vorbehalten ist. Innerhalb der Anwenderprioritätsstufen wird zwischen <em>hochprioren</em> (Klasse <em>high</em>), <em>höherprioren</em> (Klasse <em>above normal</em>), <em>normalen</em> (Klasse <em>normal</em>), <em>niederprioren</em> (Klasse <em>below normal</em>) und <em>niedrigprioren</em> (Klasse <em>idle</em>) Threads unterschieden.<br/>
Windows 2000 verwendet zur Abwicklung des Schedulings dynamische Prioritäten um eine faire Zuteilungsstrategie zu gewährleisten.</p>
         <p>Beim Einsatz von Prioritätsklassen wird typischerweise prioritätsbasiertes Round-Robin-Scheduling zwischen den Prioritätsklassen und Round-Robin-Verteilung innerhalb der Prioritätsklassen eingesetzt. Daher bedingt diese Umsetzungsform den Einsatz mehrer eigenständiger Warteschlangen, die jeweils genau einer Prioritätsklasse zugeordnet sind.</p>
         <p>Der zentrale Vorteil des Round-Robing-Verfahrens ist die einfache Umsetzung und die Unabhängigkeit von, typischerweise vorab nicht verfügbaren, Aussagen über die (erwartete) Laufzeit eines Threads. Allerdings böte die Berücksichtigung von Laufzeitaspekten eine weitere Quelle von Informationen über den Thread, die im Rahmen der Selektion des nächsten auszuführenden Threads berücksichtigung finden könnte. Im Grunde handelt es sich dabei um zusätzliche Information, die wie die Aussage über die bereits erfolgte CPU-Zuordnung im Schedulingalgorithmus der durch Beispiel <scriptRef type="example" name="pRR"/> betrachtet wurde in die Auswertung einbezogen werden kann. Ebenso wie im Beispiel geschehen, könnten Aussagen über das zurückliegende Laufzeitverhalten eines Threads gesammt und ausgewertet werden.<br/>
Einen Ansatz hierzu bildet eine Übertragung des <em>
               <a href="#SJF">Shortest-Job-First</a>
            </em>-Verfahrens auf interaktive Systeme. Hierbei werden während der Ausführung Daten über CPU-Verweildauer gesammelt. Diese werden bei der dynamischen Festlegung der Priorität geeignet einbezogen, um Threads mit kurzer Laufzeit zu bevorzugen.<br/>
Um ein realistisches Bild des veränderlichen Threadverhaltens zu erhalten bietet es sich an, nicht die gesamte bisherige Lebensdauer des Threads zur Beurteilung des Laufzeitverhaltens heranzuziehen, sondern lediglich auf jüngere Daten zurückzugreifen und diese geeignet zu gewichten. Einen Ansatz hierzu stellt die <gerquot>Alterung</gerquot> (engl. <em>aging</em>) der gesammelten Daten dar, die ein gleitendes Fenster fester Größe zur Ermittlung der Einflußfaktoren auf die Prioritätsfestlegung heranziehen. Beispiel <scriptRef type="example" name="aging"/> zeigt die Berechnung dieses Einflußfaktors.</p>
         <scriptElement type="example" name="aging" title="Aging">
            <p>Gegeben seien drei mit Prioritäten versehene Threads, so daß gilt: <code>p(t<sub>1</sub>)=2</code>, <code>p(t<sub>2</sub>)=3</code> und <code>p(t<sub>3</sub>)=1</code>. Als Schedulingalgorithmus findet das in Beispiel <scriptRef type="example" name="pRR"/> beschriebene Verfahren anwendung. Zusätzlich wird aus den während der Laufzeit ermittelten CPU-Verweildauer eine zweite Priorität dynamisch ermittelt, welcher zur ersten addiert wird.</p>
            <tabular>
               <head length="3">
                  <column title="Thread"/>
                  <column title="dynamische Priorität"/>
                  <column title="Status"/>
               </head>
               <body>
                  <row>
                     <cell>
                        <b>Schedulerlauf 1</b>:</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>1</sub>
                        </code>
                     </cell>
                     <cell>10-2+10-0=8+10=18</cell>
                     <cell>wartend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>2</sub>
                        </code>
                     </cell>
                     <cell>10-3+10-0=7+10=17</cell>
                     <cell>wartend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>3</sub>
                        </code>
                     </cell>
                     <cell>10-1+10-0=9+10=19</cell>
                     <cell>rechnend</cell>
                  </row>
                  <row>
                     <cell>
                        <b>Schedulerlauf 2</b>:</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>1</sub>
                        </code>
                     </cell>
                     <cell>18</cell>
                     <cell>wartend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>2</sub>
                        </code>
                     </cell>
                     <cell>17</cell>
                     <cell>rechnend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>3</sub>
                        </code>
                     </cell>
                     <cell>9-1+10-0/2-7=8+3=11</cell>
                     <cell>wartend</cell>
                  </row>
                  <row>
                     <cell>
                        <b>Schedulerlauf 3</b>:</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>1</sub>
                        </code>
                     </cell>
                     <cell>18</cell>
                     <cell>rechnend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>2</sub>
                        </code>
                     </cell>
                     <cell>7-3+10-0/2-2=4+8=12</cell>
                     <cell>wartend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>3</sub>
                        </code>
                     </cell>
                     <cell>11</cell>
                     <cell>wartend</cell>
                  </row>
                  <row>
                     <cell>
                        <b>Schedulerlauf 4</b>:</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>1</sub>
                        </code>
                     </cell>
                     <cell>8-2+10-0/2+5=6+50=11</cell>
                     <cell>wartend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>2</sub>
                        </code>
                     </cell>
                     <cell>12</cell>
                     <cell>rechnend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>3</sub>
                        </code>
                     </cell>
                     <cell>11</cell>
                     <cell>wartend</cell>
                  </row>
                  <row>
                     <cell>
                        <b>Schedulerlauf 5</b>:</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>1</sub>
                        </code>
                     </cell>
                     <cell>11</cell>
                     <cell>wartend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>2</sub>
                        </code>
                     </cell>
                     <cell>4-3+10-0/4+2/2-1=1+8=9</cell>
                     <cell>wartend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>3</sub>
                        </code>
                     </cell>
                     <cell>11</cell>
                     <cell>rechnend</cell>
                  </row>
               </body>
            </tabular>
         </scriptElement>
         <p>Während des ersten Schedulerlaufes liegen noch keine Daten über das dynamische Verhalten der (neu erzeugten) Threads vor, daher ist die zugehörige Prioriätskomponente durchgängig auf den Wert 0 gesetzt.<br/>
Beim zweiten Durchlauf des Schedulers wird Thread <code>t<sub>2</sub>
            </code> zur Ausführung selektiert. Zusätzlich werden die gesammelten Ablaufdaten des ausgeführten Threads mit der Priorität 7 bewertet und bei der Neufestlegung der dynamischen Priorität entsprechend berücksichtigt.<br/>
Die dritte Anwendung des Scheduleralgorithmus liefert <code>t<sub>1</sub>
            </code> als Thread mit der höchsten dynamischen Priorität und teil diesem die CPU zu.<br/>
Während seiner Ausführung werden auch über ihn dynamische Daten gesammelt, die beim vierten Schedulerlauf entsprechend in die Neufestlegung der dynamischen Priorität Eingang finden.<br/>
Der vierte Schedulerlauf wählt bereits zum zweiten Mal den mit der niedersten statischen Thread-Priorität versehenen <code>t<sub>3</sub>
            </code> zur Ausführung aus, da der Zuteilung-Algorithmus -- gestützt auf den gesammelten Verhaltensdaten -- seine erneute Selektion empfiehlt.<br/>
Der fünfte Durchlauf des Schedulers selektiert wahlfrei <code>t<sub>3</sub>
            </code> zur Ausführung, da seine dynamische Priorität identisch zu <code>t<sub>3</sub>
            </code> ist und beide Thread bisher gleichhäufig ausgeführt wurden. Thread <code>t<sub>2</sub>
            </code> erhält die dynamische Priorität 9 zugeteilt. Gleichzeitig zeigt die Berechung seiner Priorität die Wirkung des <em>agings</em>, bei dem mehrere historische Werte, nach ihrem Alter gewichtet, in die Berechung einbezogen werden.</p>
         <p>Insgesamt zeigt das Beispiel auch die Wirkungsmacht des Einbezugs von Laufzeitinformation in die Prioritätsfestlegung. So wird Thread <code>t<sub>2</sub>
            </code> -- obwohl er über die niedrigste statische Priorität verfügt --, vermöge der positiven Laufzeitdaten, ebenso häufig ausgeführt wie <code>t<sub>3</sub>
            </code>, der mit der höchsten statischen Priorität ausgestattet wurde.</p>
         <p>Eine alternative Schedulingvariante ergibt sich, wenn die Zielsetzung der größtmöglichen Fairness in den Vordergrund gerückt wird. So ergibt sich durch die Verfolgung der Zielsetzung jedem Thread möglichst denselben Anteil an CPU-Zeit zuzuteilen eine <b>Scheduling-Garantie</b> auf die sich jeder Anwender verlassen kann.<br/>
Als Ziel kann hierbei verfolgt werden jedem Thread relativ zu seiner Lebenszeit dieselbe Menge Zuordnungen zuteil werden zu lassen. Beispiel <scriptRef type="example" name="GS"/> zeigt einen exemplarischen Ablauf:</p>
         <scriptElement type="example" name="GS">
            <tabular>
               <head length="4">
                  <column title="Thread"/>
                  <column title="Alter"/>
                  <column title="bisherige Zuteilungen"/>
                  <column title="Status"/>
               </head>
               <body>
                  <row>
                     <cell>
                        <b>Schedulerlauf 1</b>:</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>1</sub>
                        </code>
                     </cell>
                     <cell>1</cell>
                     <cell>0</cell>
                     <cell>rechnend</cell>
                  </row>
                  <row>
                     <cell>
                        <b>Schedulerlauf 2</b>:</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>1</sub>
                        </code>
                     </cell>
                     <cell>2</cell>
                     <cell>1</cell>
                     <cell>rechnend</cell>
                  </row>
                  <row>
                     <cell>
                        <b>Schedulerlauf 3</b>:</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>1</sub>
                        </code>
                     </cell>
                     <cell>3</cell>
                     <cell>2</cell>
                     <cell>wartend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>2</sub>
                        </code>
                     </cell>
                     <cell>1</cell>
                     <cell>0</cell>
                     <cell>rechnend</cell>
                  </row>
                  <row>
                     <cell>
                        <b>Schedulerlauf 4</b>:</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>1</sub>
                        </code>
                     </cell>
                     <cell>4</cell>
                     <cell>2</cell>
                     <cell>rechnend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>2</sub>
                        </code>
                     </cell>
                     <cell>2</cell>
                     <cell>1</cell>
                     <cell>wartend</cell>
                  </row>
                  <row>
                     <cell>
                        <b>Schedulerlauf 5</b>:</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>1</sub>
                        </code>
                     </cell>
                     <cell>5</cell>
                     <cell>3</cell>
                     <cell>wartend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>2</sub>
                        </code>
                     </cell>
                     <cell>3</cell>
                     <cell>1</cell>
                     <cell>rechnend</cell>
                  </row>
                  <row>
                     <cell>
                        <b>Schedulerlauf 6</b>:</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>1</sub>
                        </code>
                     </cell>
                     <cell>4</cell>
                     <cell>2</cell>
                     <cell>rechnend</cell>
                  </row>
                  <row>
                     <cell>
                        <code>t<sub>2</sub>
                        </code>
                     </cell>
                     <cell>3</cell>
                     <cell>2</cell>
                     <cell>wartend</cell>
                  </row>
               </body>
            </tabular>
         </scriptElement>
         <p>Das Beispiel zeigt fünf aufeinanderfolgende Zurodnungen unter Anwendung garantierter Zuteilung. Zur CPU-Zuordnung ausgewählt wird jeweils der Thread, dessen Alter (d.h. Verweildauer im System) gegenüber den bisher erfolgten Zuteilungen am kleinsten ist.</p>
         <p>Die dargestellte Schedulingvariante berücksichtigt ausschließlich die Anzahl der laufenden Threads und verspricht diesen Gleichbehandlung. Eine unter dem Namen <b>
               <keyword>Fair-Share Scheduling</keyword>
            </b> bekannte Variante dieses Vorgehens betrachtet nicht die Anzahl der Threads, sondern die Anzahl der sie besitzenden Anwender und garantiert die Gleichbehandlung aller Anwender statt der durch sie gestarteten Berechnungsaufgaben.<br/>
Ziel dieser Modifikation des Algorithmus ist es die inhärente Bevorzugung derjenigen Anwender, die viele Threads starten, zu eliminieren.<br/>
Eine Umsetzungsmöglichkeit wäre daher die Nutzung von garantiertem Scheduling zwischen den Anwendern und Zuordnung der Threads eines Anwenders im Round-Robin-Verfahren.</p>
         <p>Das <b>Lotterie-Scheduling</b> greift die Idee der Fairness auf und steigert das Versprechen des Algorithmus der garantierten Zuordnung sogar noch. So werden beim Lotterie-ähnlichen Scheduling Lose an alle im System laufenden Threads verteilt. Jede zu vergebende Zeitscheibe wird unter den rechenwilligen Threads <gerquot>verlost</gerquot>. Gewinnt das Los eines Threads, so erhält er die CPU zugeordnet.<br/>
Der zugrundeligende Algorithmus ist vergleichsweise einfach umzusetzen und gestattet sogar, durch die Verteilung von mehr als einem Los an einen Thread, die Nachbildung von Prioriätten. Allerdings hängt die praktische Einsetzbarkeit stark von der Qualität der zur Verfügung stehenden Zufallszahlen, welche die Basis des <gerquot>Glücksspiels</gerquot> bilden ab. Sind diese nicht gleichverteilt, sondern treten gehäuft oder gar periodisch auf, so kann dies zur unerwünschten Bevorzugung einzelner Threads führen.</p>
         <p>Die Windows 2000 Systemfamilie setzt eine Variante des garantierten Schedulings ein, welche jedem im System laufenden Thread grundsätzlich denselben CPU-Anteil (Quantum) garantiert. Zusätzlich verfügt jeder Thread über eine Prioritätsebene, welche seine Zuordnungshäufigkeit steuert. Die Workstations-Editionen der Windows-Betriebssysteme sehen zusätzlich, beispielsweise zur Steigerung derjenigen Threads die einem Programm zugeordnet sind, mit welchem der Anwender aktuell arbeitet, Prioritäts-<em>Boosts</em> vor, die kurzfristig die Priorität eines Threads steigern können.</p>
         <p>Das Linux-Betriebssystem verfügt seit der Version 2.6 über einen neuen Scheduleransatz, welcher die faire CPU-Zuteilung auch bei hohen Systemlasten garantieren soll. Da Linux im Betriebssystemkern ausschließlich Prozesse behandelt berücksichtigt der Schedulingalgorithmus auch ausschließlich diese als kleine Einheit der Rechenzeitverteilung.<br/>
Ziel des Schedulingalgorithmus ist es größtmögliche Skalierbarkeit zu verwirklichen und die CPU-Zuteilung in konstanten Zeitintervallen zu garantieren. Der Schedulingalgorithmus besitzt daher die Komplexität <em>O(1)</em>.</p>
         <p>Grundlegende Datenstruktur des Schedulers ist die in <illustrationLink ref="schedLinux"/> zusammengestellt.</p>
         <illustration id="schedLinux" width="500" caption="Datenstruktur des Linux-Schedulers" gfx="sysarch/schedLinux.png"/>
         <hint type="TODO">
            <p>Hier geht's demnächst weiter ...</p>
         </hint>
         <scriptElement type="links" title="Weiterführende Links">
            <link>
               <a href="http://www.llnl.gov/computing/tutorials/workshops/workshop/pthreads/MAIN.html">PThreads-Tutorial</a>
            </link>
            <link>
               <a href="http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html">YoLinux Tutorial: POSIX thread (pthread) libraries</a>
            </link>
            <link>
               <a href="../javaThreads/index.html">Vorlesung <em>Java Threads</em>
               </a>
            </link>
         </scriptElement>
      </region>
      <topic name="keywords">Schlagwortverzeichnis</topic>
      <keywordList/>
   </body>
</document>