Laufzeitsystem - Runtime system

In der Computerprogrammierung implementiert ein Laufzeitsystem , auch Laufzeitumgebung genannt , hauptsächlich Teile eines Ausführungsmodells . Dies ist nicht zu verwechseln mit der Laufzeit- Lebenszyklusphase eines Programms, während der das Laufzeitsystem in Betrieb ist. Wenn das Laufzeitsystem getrennt von der Laufzeitumgebung (RTE) behandelt wird, kann die erste als ein spezifischer Teil der Anwendungssoftware (IDE) definiert werden, die zum Programmieren verwendet wird , eine Software, die dem Programmierer eine bequemere Umgebung zum Ausführen von Programmen bietet bei ihrer Herstellung ( testen und ähnliches) , während die zweite (RTE) die sehr wäre Instanz eines Ausführungsmodell des entwickelten Programms angelegt wird , das selbst dann in der vorher erwähnten laufen Laufzeitsystem .

Die meisten Programmiersprachen haben eine Art Laufzeitsystem, das eine Umgebung bereitstellt, in der Programme ausgeführt werden. Diese Umgebung kann eine Reihe von Fragen , einschließlich der Adresse Management von Anwendungsspeicher , wie das Programm greift auf Variablen , Mechanismen für die Parameter zwischen Passieren Verfahren , mit dem eine Schnittstelle Betriebssystem und auf andere Weise. Der Compiler trifft abhängig vom jeweiligen Laufzeitsystem Annahmen, um korrekten Code zu generieren. Normalerweise trägt das Laufzeitsystem eine gewisse Verantwortung für das Einrichten und Verwalten des Stapels und des Heaps und kann Funktionen wie Garbage Collection , Threads oder andere dynamische Funktionen enthalten, die in die Sprache integriert sind.

Überblick

Jede Programmiersprache spezifiziert ein Ausführungsmodell, und viele implementieren zumindest einen Teil dieses Modells in einem Laufzeitsystem. Eine mögliche Definition des Laufzeitsystemverhaltens ist unter anderem "jedes Verhalten, das nicht direkt dem Programm selbst zuzuschreiben ist". Diese Definition umfasst das Ablegen von Parametern auf den Stack vor Funktionsaufrufen, die parallele Ausführung verwandter Verhaltensweisen und die Festplatten- E/A .

Nach dieser Definition hat im Wesentlichen jede Sprache ein Laufzeitsystem, einschließlich kompilierter Sprachen , interpretierter Sprachen und eingebetteter domänenspezifischer Sprachen . Sogar API- aufgerufene eigenständige Ausführungsmodelle, wie Pthreads ( POSIX- Threads ), verfügen über ein Laufzeitsystem, das das Verhalten des Ausführungsmodells implementiert.

Die meisten wissenschaftlichen Arbeiten zu Laufzeitsystemen konzentrieren sich auf die Implementierungsdetails paralleler Laufzeitsysteme. Ein bemerkenswertes Beispiel für ein paralleles Laufzeitsystem ist Cilk , ein beliebtes paralleles Programmiermodell. Das Proto-Runtime-Toolkit wurde erstellt, um die Erstellung paralleler Laufzeitsysteme zu vereinfachen.

Neben dem Verhalten des Ausführungsmodells kann ein Laufzeitsystem auch Unterstützungsdienste wie Typprüfung , Debugging oder Codegenerierung und -optimierung durchführen .

Bezug zu Laufzeitumgebungen

Das Laufzeitsystem ist auch das Gateway, über das ein laufendes Programm mit der Laufzeitumgebung interagiert . Die Laufzeitumgebung umfasst nicht nur zugängliche Zustandswerte, sondern auch aktive Entitäten, mit denen das Programm während der Ausführung interagieren kann. Zum Beispiel Umgebungsvariablen sind Merkmale von vielen Betriebssystemen und ist Teil der Laufzeitumgebung; ein laufendes Programm kann über das Laufzeitsystem darauf zugreifen. Ebenso sind Hardwaregeräte wie Festplatten oder DVD-Laufwerke aktive Einheiten, mit denen ein Programm über ein Laufzeitsystem interagieren kann.

Eine einzigartige Anwendung einer Laufzeitumgebung ist die Verwendung innerhalb eines Betriebssystems, das nur die Ausführung zulässt. Mit anderen Worten, vom Booten bis zum Ausschalten ist das gesamte Betriebssystem nur für die Anwendung(en) bestimmt, die in dieser Laufzeitumgebung ausgeführt werden. Jeder andere Code, der versucht, ausgeführt zu werden, oder Fehler in der Anwendung(en) unterbrechen die Laufzeitumgebung. Das Unterbrechen der Laufzeitumgebung wiederum unterbricht das Betriebssystem, stoppt die gesamte Verarbeitung und erfordert einen Neustart. Wenn der Bootvorgang aus einem Nur-Lese-Speicher erfolgt, wird ein extrem sicheres, einfaches Single-Mission-System erstellt.

Beispiele für solche direkt gebündelten Laufzeitsysteme sind:

  • Zwischen 1983 und 1984 bot Digital Research mehrere seiner Geschäfts- und Bildungsanwendungen für den IBM PC auf bootfähigen Disketten an, gebündelt mit SpeedStart CP/M-86 , einer reduzierten Version von CP/M-86 als Laufzeitumgebung.
  • Einige eigenständige Versionen von Ventura Publisher (1986–1993), Artline (1988–1991), Timeworks Publisher (1988–1991) und ViewMAX (1990–1992) enthielten spezielle Laufzeitversionen des GEM von Digital Research als Laufzeitumgebung.
  • In den späten 1990er Jahren war der Befehlszeilenprozessor 4DOS von JP Software optional in einer speziellen Laufzeitversion erhältlich, die mit BATCOMP vorkompilierten und verschlüsselten Batch-Jobs verknüpft werden konnte, um unveränderbare ausführbare Dateien aus Batch-Skripten zu erstellen und auf Systemen ohne installiertes 4DOS auszuführen .

Beispiele

Das Laufzeitsystem der Sprache C ist ein bestimmter Satz von Anweisungen, der vom Compiler in das ausführbare Image eingefügt wird. Diese Anweisungen verwalten unter anderem den Prozessstack, schaffen Platz für lokale Variablen und kopieren Funktionsaufrufparameter auf den Stapel.

Es gibt oft keine klaren Kriterien, um zu bestimmen, welches Sprachverhalten Teil des Laufzeitsystems selbst ist und welches von einem bestimmten Quellprogramm bestimmt werden kann. In C ist der Aufbau des Stacks beispielsweise Teil des Laufzeitsystems. Es wird nicht durch die Semantik eines einzelnen Programms bestimmt, da das Verhalten global invariant ist: es gilt für alle Ausführungen. Dieses systematische Verhalten implementiert das Ausführungsmodell der Sprache, im Gegensatz zur Implementierung der Semantik des jeweiligen Programms (bei der Text direkt in Code übersetzt wird, der Ergebnisse berechnet).

Diese Trennung zwischen der Semantik eines bestimmten Programms und der Laufzeitumgebung spiegelt sich in den verschiedenen Arten der Kompilierung eines Programms wider: Kompilieren des Quellcodes in eine Objektdatei , die alle Funktionen enthält, versus Kompilieren eines gesamten Programms in eine ausführbare Binärdatei. Die Objektdatei enthält nur Assemblycode, der für die enthaltenen Funktionen relevant ist, während die ausführbare Binärdatei zusätzlichen Code enthält, der die Laufzeitumgebung implementiert. Einerseits können in der Objektdatei Informationen aus der Laufzeitumgebung fehlen, die durch das Verknüpfen von . Andererseits hängt der Code in der Objektdatei immer noch von Annahmen im Laufzeitsystem ab; zum Beispiel kann eine Funktion Parameter aus einem bestimmten Register oder Stack-Speicherort lesen, abhängig von der Aufrufkonvention, die von der Laufzeitumgebung verwendet wird.

Ein weiteres Beispiel ist die Verwendung einer Anwendungsprogrammierschnittstelle (API) zur Interaktion mit einem Laufzeitsystem. Die Aufrufe dieser API sehen genauso aus wie Aufrufe einer regulären Softwarebibliothek , jedoch ändert sich irgendwann während des Aufrufs das Ausführungsmodell. Das Laufzeitsystem implementiert ein Ausführungsmodell, das sich von dem der Sprache unterscheidet, in der die Bibliothek geschrieben wurde. Eine Person, die den Code einer normalen Bibliothek liest, kann das Verhalten der Bibliothek verstehen, indem sie nur die Sprache kennt, in der die Bibliothek geschrieben wurde. Eine Person, die den Code der API liest, die ein Laufzeitsystem aufruft, kann jedoch die Verhalten des API-Aufrufs nur durch Kenntnis der Sprache, in der der Aufruf geschrieben wurde. Irgendwann hört das Ausführungsmodell über einen Mechanismus auf, das der Sprache zu sein, in der der Aufruf geschrieben wurde, und wechselt zu dem von der Laufzeit implementierten Ausführungsmodell System. Der Trap-Befehl ist beispielsweise ein Verfahren zum Umschalten von Ausführungsmodellen. Dieser Unterschied unterscheidet ein API-aufgerufenes Ausführungsmodell wie Pthreads von einer üblichen Softwarebibliothek. Sowohl Pthreads-Aufrufe als auch Softwarebibliotheksaufrufe werden über eine API aufgerufen, aber das Verhalten von Pthreads kann nicht in Bezug auf die Sprache des Aufrufs verstanden werden. Vielmehr bringen Pthreads-Aufrufe ein externes Ausführungsmodell ins Spiel, das vom Pthreads-Laufzeitsystem implementiert wird (dieses Laufzeitsystem ist oft der Betriebssystemkernel).

Als extremes Beispiel kann die physikalische CPU selbst als Implementierung des Laufzeitsystems einer bestimmten Assemblersprache angesehen werden. In dieser Ansicht wird das Ausführungsmodell durch die physischen CPU- und Speichersysteme implementiert. Analog dazu werden Laufzeitsysteme für höhere Sprachen selbst mit einigen anderen Sprachen realisiert. Dadurch entsteht eine Hierarchie von Laufzeitsystemen, wobei die CPU selbst – oder eigentlich ihre Logik auf der Mikrocode- Schicht oder darunter – als das unterste Laufzeitsystem fungiert.

Erweiterte Funktionen

Einige kompilierte oder interpretierte Sprachen stellen eine Schnittstelle bereit, die es dem Anwendungscode ermöglicht, direkt mit dem Laufzeitsystem zu interagieren. Ein Beispiel ist die ThreadKlasse in der Java-Sprache . Die Klasse ermöglicht Code (der von einem Thread animiert wird) Dinge wie das Starten und Stoppen anderer Threads. Normalerweise sind Kernaspekte des Verhaltens einer Sprache wie Aufgabenplanung und Ressourcenverwaltung auf diese Weise nicht zugänglich.

Von einem Laufzeitsystem implementierte Verhaltensweisen auf höherer Ebene können Aufgaben wie das Zeichnen von Text auf dem Bildschirm oder das Herstellen einer Internetverbindung umfassen. Es ist oft der Fall, dass Betriebssysteme diese Art von Verhalten ebenfalls bereitstellen, und wenn verfügbar, wird das Laufzeitsystem als Abstraktionsschicht implementiert , die den Aufruf des Laufzeitsystems in einen Aufruf des Betriebssystems übersetzt. Dies verbirgt die Komplexität oder Variationen der Dienste, die von verschiedenen Betriebssystemen angeboten werden. Dies impliziert auch, dass der OS-Kernel selbst als ein Laufzeitsystem betrachtet werden kann und dass der Satz von OS-Aufrufen, die OS-Verhalten aufrufen, als Interaktionen mit einem Laufzeitsystem betrachtet werden können.

Im Grenzfall kann das Laufzeitsystem Dienste wie eine P-Code-Maschine oder eine virtuelle Maschine bereitstellen , die sogar den Befehlssatz des Prozessors verbergen . Dies ist der Ansatz, den viele interpretierte Sprachen wie AWK und einige Sprachen wie Java verfolgen , die in einen maschinenunabhängigen Zwischenrepräsentationscode (wie bytecode ) kompiliert werden sollen . Diese Anordnung vereinfacht die Aufgabe der Sprachimplementierung und ihre Anpassung an unterschiedliche Maschinen und verbessert die Effizienz anspruchsvoller Sprachmerkmale wie z. B. Reflexion . Es ermöglicht auch die Ausführung desselben Programms auf jedem Computer ohne einen expliziten Neukompilierungsschritt, eine Funktion, die seit der Verbreitung des World Wide Web sehr wichtig geworden ist . Um die Ausführung zu beschleunigen, bieten einige Laufzeitsysteme die Just-in-Time-Kompilierung in Maschinencode.

Ein moderner Aspekt von Laufzeitsystemen ist das parallele Ausführungsverhalten, wie das Verhalten von Mutex-Konstrukten in Pthreads und parallelen Abschnittskonstrukten in OpenMP . Ein Laufzeitsystem mit solchen parallelen Ausführungsverhalten kann gemäß dem Proto-Laufzeit-Ansatz modularisiert werden.

Geschichte

Bemerkenswerte frühe Beispiele für Laufzeitsysteme sind die Interpreter für BASIC und Lisp . Diese Umgebungen enthielten auch einen Garbage Collector . Forth ist ein frühes Beispiel für eine Sprache, die entworfen wurde, um in Zwischenrepräsentationscode kompiliert zu werden; sein Laufzeitsystem war eine virtuelle Maschine, die diesen Code interpretierte. Ein weiteres beliebtes, wenn theoretisch Beispiel ist Donald Knuth ‚s MIX - Computer.

In C und späteren Sprachen, die dynamische Speicherzuweisung unterstützten, enthielt das Laufzeitsystem auch eine Bibliothek, die den Speicherpool des Programms verwaltete.

In den objektorientierten Programmiersprachen war das Laufzeitsystem oft auch für die dynamische Typprüfung und das Auflösen von Methodenreferenzen verantwortlich.

Siehe auch

Verweise

Weiterlesen