3 Programmierumgebung
Transcription
3 Programmierumgebung
Praktikum zur Lehrveranstaltung Betriebssysteme Seite 3 - 1 3 Programmierumgebung Damit Sie Ihre Programme in C und Java entwickeln können, müssen entsprechende Programmierumgebungen zur Verfügung stehen. Im Kapitel 1 haben Sie bereits gelernt, wie Sie in der Linux-Welt der Hochschule Fulda eine Compiler-Version für C oder Java auswählen können. In der „Microsoft Windows“-Welt müssen ebenfalls Programmierumgebungen eingerichtet werden, wenn Sie an Ihren Programmen auch zu Hause arbeiten wollen und keine reine UNIX-Welt (z. B. „Linux“ oder „Solaris x86“) inkl. Programmierumgebung installiert haben. Wenn Sie eine C-Programmierumgebung unter Windows installieren wollen, können Sie zwischen verschiedenen kostenfreien Varianten auswählen. 1) Die Hochschule Fulda hat mit Microsoft ein Rahmenabkommen, über das Sie fast alle Microsoft-Produkte kostenfrei im Rahmen Ihres Studiums einsetzen und lizenzieren können, z. B. auch die Programmierumgebung für C. 2) Die integrierte Entwicklungsumgebung „Code::Blocks“ ist eine freie Software und darf für beliebige Dinge benutzt werden. 3) Die integrierte Entwicklungsumgebung „lcc-win32“ steht für eine private, nicht kommerzielle Nutzung frei zur Verfügung. Sie enthält mehrere Hundert Seiten Dokumentationen (inkl. umfangreichem C-Tutorial). 4) Sie können unter Windows die UNIX-Umgebung Cygwin inkl. GNU-C-Compiler installieren und konfigurieren. Der Vorteil dieser Lösung liegt darin, dass Sie Cygwin wie ein normales Windows-Programm starten und stoppen können und gleichzeitig eine gute UNIXUmgebung für die Programmentwicklung zur Verfügung haben. Neben C benötigen Sie noch eine Java-Programmierumgebung. Sie können die erforderliche Software beispielsweise von „http://www.oracle.com/technetwork/java“ herunterladen und installieren. Für das „JDK 8 Update 74“ würden Sie z. B. folgende Dateien installieren. jdk-8u74-windows-i586.exe (32-Bit Betriebssystem), jdk-8u74-windows-x64.exe (64-Bit Betriebssystem), jdk-8u74-docs-all.zip. Falls Sie das 64-Bit Betriebssystem „Windows 7 x64“ oder neuer benutzen, sollten Sie eventuell beide Java-Versionen installieren, damit Java sowohl im 32-Bit als auch im 64-Bit Browser zur Verfügung steht. Die 32-Bit Version wird z. B. in „c:\Programme (x86)\jdk1.8.0_74“ und die 64Bit Version in „c:\Programme\jdk1.8.0_74“ installiert. Führen Sie „jdk-8u74-windows-i586.exe“ und/oder „jdk-8u74-windows-x64.exe“ aus und ändern Sie ggf. den Pfad analog zur obigen Vorgabe. Packen Sie die Datei „jdk-8u74-docs-all.zip“ im Verzeichnis „<Pfad>\jdk1.8.0_74“ aus (ggf. für die 32- und 64-Bit Version). Wenn Sie Java in einem Kommandozeilenfenster (cmd.exe, powershell.exe) benutzen wollen, müssen Sie noch die Systemumgebungsvariablen Path, JAVA_HOME und CLASSPATH einrichten bzw. anpassen. Start → Systemsteuerung [→ System und Sicherheit] → System → Erweitert[e Systemeinstellungen] → Umgebungsvariablen Erzeugen Sie eine neue Systemumgebungsvariable JAVA_HOME und weisen Sie ihr z. B. den Wert „c:\Programme\jdk1.8.0_74“ zu. Der Variablen CLASSPATH weisen Sie den Wert „.“ zu. Hochschule Fulda, Fachbereich AI, Prof. Dr. S. Groß Praktikum zur Lehrveranstaltung Betriebssysteme Seite 3 - 2 Am Ende der Umgebungsvariablen „Path“ fügen Sie den Wert „;%JAVA_HOME%\bin“ hinzu. Falls Sie keine Änderungen am System vornehmen wollen, können Sie auch die Datei „java1.8.0_74_env.bat“ aus dem Verzeichnis „cmd“ des Programmarchivs dieser Lehrveranstaltung benutzen, um die Umgebung temporär in einem Kommandozeilenfenster zur Verfügung zu stellen. Gegebenenfalls müssen Sie die Datei an Ihre Java-Version und -Installation anpassen. Wenn Sie unter Cygwin Handbuchseiten zu Java haben wollen, können Sie das Java-Paket für Linux herunterladen und auspacken. Sie würden dann den Verzeichnisbaum „man\man1“ in das Java-Installationsverzeichnis (z. B. c:\Programme\jdk1.8.0_74) kopieren. Die Java-Umgebung in Cygwin können Sie z. B. benutzen, wenn Sie meine Cygwin-Umgebung (cygwin-env.tar.gz von meiner Web-Seite zu Cygwin) installieren. Wenn alles erfolgreich durchgeführt worden ist, liefert das Kommando „man javac“ jetzt die Handbuchseite zu „javac“. Wie Sie im Kapitel 2 gelernt haben, wird Ihr C-Quellcode zuerst von einem Präprozessor „aufbereitet“, bevor ihn der Compiler sieht. Bei einigen Compilern ist der Präprozessor ein eigenes Programm im Compiler-Verzeichnis, während andere Compiler eine Präprozessor-Bibliothek benutzen, die sie gemeinsam mit dem Programm „cpp“ verwenden. tyr bs_praktikum 120 info /usr/local/gcc-4.9.2/share/info/cppinternals.info ... The GNU C preprocessor is implemented as a library, "cpplib", so it can be easily shared between a stand-alone preprocessor, and a preprocessor integrated with the C, C++ and Objective-C front ends. It is also ... Wenn Sie ein Programm entwickeln, sind an diesem Prozess sehr viele verschiedene Programme beteiligt. Die nachfolgende Abbildung gibt Ihnen einen Überblick darüber, welche Programme Sie für die Erstellung eines Programms in der Programmiersprache C benötigen. Editor C-Quellcode (name.c) IncludeDateien Präprozessor cc -E ... cpp erweiterte Datei cc -S ... C-Compiler Assembler-Datei (name.s) cc cc -c ... Objektdateien (*.o) as Assembler temporäre Objektdatei (name.o) Bibliotheksverwalter Standard CBibliotheken, ... Binder Objektbibliothek (libxyz.a) ld ausführbares Programm (a.out) ar cc -G ... cc -r ... dynamisch oder statisch ladbare Objektmodule (*.so, *.o) Hochschule Fulda, Fachbereich AI, Prof. Dr. S. Groß Praktikum zur Lehrveranstaltung Betriebssysteme Seite 3 - 3 Die Arbeit beginnt immer mit einem Editor, in dem Sie Ihren Quellcode schreiben. In der UNIXWelt (inkl. Cygwin) sollten Sie „xemacs“ benutzen. In der „Microsoft Windows“-Welt werden Sie fast immer mit einer integrierten Entwicklungsumgebung und dem Editor dieser Umgebung arbeiten. Wenn Ihr C-Programm als Datei vorliegt, können Sie in einem Kommandozeilenfenster die Datei übersetzen und das Programm ausführen, wenn Sie Ihre Umgebung richtig eingerichtet haben. Beispiel: cc floatingpoint.c floatingpoint cc unter UNIX gcc floatingpoint.c floatingpoint gcc unter UNIX cl floatingpoint.c floatingpoint Microsoft Visual Studio Ihnen ist vielleicht aufgefallen, dass in keinem Fall der Präprozessor, Assembler oder Binder explizit aufgerufen wurde, da nur Programme benutzt werden, die den Übersetzungsvorgang steuern. „gcc“ würde irgendwann auch „as“ benötigen, wie Sie der folgenden Ausgabe entnehmen können. eiger x 13 mv /usr/bin/as /usr/bin/as.old eiger x 14 gcc floatingpoint.c gcc: installation problem, cannot exec 'as': No such file or directory eiger x 15 mv /usr/bin/as.old /usr/bin/as eiger x 16 gcc floatingpoint.c Normalerweise müssen Sie auf der Kommandozeile also auch nicht mehr tippen als in der integrierten Entwicklungsumgebung („Compile & Run“ in der Menüleiste, <F9>-Taste oder etwas ähnliches), um ein Programm zu erzeugen. Trotzdem haben integrierte Entwicklungsumgebungen einen großen Vorteil: Sie bieten im Allgemeinen ein Hilfesystem und einen integrierten „Debugger“ zur Fehlersuche an, sodass die Entwicklung des Programms u. U. etwas einfacher ist. Im Linux-Labor können Sie die integrierte Entwicklungsumgebung von „Oracle Solaris Studio“ (Kommando: solstudio) oder Eclipse für C-Programme benutzen. Die Compiler-Optionen in der obigen Abbildung sind natürlich spezifisch für einen Compiler, obwohl (fast) alle Compiler Optionen für ähnliche Aufgaben zur Verfügung stellen. Eine Kurzdarstellung der Optionen erhalten Sie in einem Kommandozeilenfenster folgendermaßen: Microsoft Visual Studio GNU C-Compiler Oracle Solaris Studio C-Compiler Intel C-Compiler cl /? gcc --help cc –flags icc –help oder icc –-help Dateien mit Assemblercode, Objektcode, Bibliotheken und ausführbare Programme hängen vom Betriebssystem und/oder der Prozessorarchitektur ab und müssen in heterogenen Umgebungen in speziellen Verzeichnissen abgelegt werden oder unterschiedliche Namen erhalten, aus denen das Betriebssystem und die Prozessorarchitektur hervorgehen. In Kapitel 1 haben Sie gelernt, dass diese Dateien in der Hochschule Fulda in speziellen Verzeichnissen gespeichert werden. In großen Projekten werden mehrere Hundert oder sogar mehrere Tausend Dateien erstellt, die für ein Programm (z. B. „xemacs“) oder eine Bibliothek (z. B. „Open MPI“) benötigt werden. Hochschule Fulda, Fachbereich AI, Prof. Dr. S. Groß Praktikum zur Lehrveranstaltung Betriebssysteme Seite 3 - 4 Wenn Sie beispielsweise ein Mathematik-Programm erstellen, wollen Sie Ihr Programm nicht mit „sin.o“, „cos.o“, „exp.o“ usw. binden, sondern Sie möchten Ihr Programm mit einer mathematischen Bibliothek binden, in der alle Funktionen enthalten sind. Jede C-Programmierumgebung enthält deshalb Programme, mit denen Sie solche Bibliotheken erstellen können. Sie können Ihre Programme mit dynamischen (UNIX: shared objects (*.so oder *.so.*), Microsoft Windows: dynamic link library (*.dll)) und/oder statischen Bibliotheken (UNIX: *.a, Microsoft Windows: *.lib) binden. Heute werden meistens dynamische Bibliotheken benutzt, da sie gegenüber den statischen Bibliotheken folgende Vorteile aufweisen. 1) Sie sparen Speicherplatz. a) Die Bibliotheksfunktionen befinden sich nur einmal auf der Festplatte und nicht im Code von jedem Programm. b) Die Bibliotheksfunktionen befinden sich nur einmal im Hauptspeicher, d. h., dass der Hauptspeicher besser ausgenutzt wird, weil mehrere Programme dieselbe Kopie der Funktion gleichzeitig benutzen können. Außerdem ist der Datentransfer zwischen Haupt- und Hintergrundspeicher (swapping, paging) wesentlich geringer, da die Funktion nur einmal transportiert werden muss und nicht mit jedem Programm, das die Funktion benutzt. 2) Dynamische Bibliotheken können einfacher erweitert/aktualisiert werden, da sie durch neue Versionen ersetzt werden können, solange die Schnittstellen alter Funktionen nicht geändert werden (Fehlerbehebung, Anpassung an neue Hardware (z. B. neue Grafikkarten), usw.). Bei statischen Bibliotheken müssen alle Programme ggf. neu übersetzt werden. 3) Neue Landessprachen können auf einfache Weise hinzugefügt werden. 4) Programme können u. U. schneller geladen werden, wenn Sie bestimmte Bibliotheken am Anfang noch nicht benötigen. Dynamische Bibliotheken haben den Nachteil, dass sie einen Mechanismus benötigen, mit dessen Hilfe Funktionen der Bibliothek zur Laufzeit des Programms geladen werden können. Ein weiterer Nachteil besteht darin, dass Programme nicht lauffähig sind, wenn die dynamische Bibliothek nicht existiert (z. B., weil das Bibliotheksverzeichnis nicht zugreifbar ist oder weil die Bibliothek nach einer Aktualisierung gelöscht worden ist). Statisch gebundene Programme haben diese Nachteile nicht. Alle Systemprogramme, die für einen Notfall erforderlich sind (UNIX: sh, mount, ...), sollten deshalb immer statisch gebunden werden, damit sie im Notfall auch funktionieren. Im Folgenden wird gezeigt, wie Sie unter UNIX dynamische und statische Bibliotheken erzeugen können und wie Sie Programme mit statischen und dynamischen Bibliotheken binden können. In der Lehrveranstaltung „BG14: Betriebssysteme“ werden Programme erstellt, in denen parallele Abläufe synchronisiert werden sollen. Da der Schwerpunkt auf der Synchronisation und nicht auf der Erzeugung paralleler Abläufe liegt, wird in der Veranstaltung eine Bibliothek zur Verfügung gestellt, die unter UNIX und Microsoft Windows u. a. die Funktion „parallel“ zur Verfügung stellt, sodass Sie Ihre Programme auf einfache Weise unter UNIX oder Windows entwickeln und testen können. Die folgenden Kommandos stammen aus der Programmierumgebung der „Oracle Solaris Studio“-Entwicklungsumgebung. Hochschule Fulda, Fachbereich AI, Prof. Dr. S. Groß Praktikum zur Lehrveranstaltung Betriebssysteme 1) Seite 3 - 5 Dynamische Bibliothek erstellen. cc –KPIC -G -o libparallel.so parallel.c (gcc –fPIC -shared -o libparallel.so parallel.c) (icc –fpic -shared -o libparallel.so parallel.c) 2) Objektdatei erstellen. cc -c parallel.c 3) Objektdatei in statische Bibliothek einbinden. ar -rcv parallel.a parallel.o a - parallel.o ar: writing parallel.a 4) Programme erzeugen. „-lparallel“ bindet das Programm mit der dynamischen Bibliothek libparallel.so, d. h., dass die Option „-l“ nur den Namen der Bibliothek ohne „lib“ und ohne „.so“ benutzt. Warum werden die Optionen „-R“ und „-L“ benutzt? cc -o sema-o semaphor.c parallel.o -lpthread cc -o sema-a semaphor.c parallel.a -lpthread cc -o sema-so -R`pwd` -L`pwd` semaphor.c -lparallel –lpthread (gcc -o sema-so -Wl,-rpath `pwd` -L`pwd` semaphor.c -lparallel –lpthread) (icc -o sema-so -Wl,-rpath `pwd` -L`pwd` semaphor.c -lparallel –lpthread) 5) Wie groß sind die Bibliotheken, die Objektdatei und die Programme? -rwxr-xr-x -rw-r--r--rw-r--r--rwxr-xr-x -rwxr-xr-x -rwxr-xr-x 6) 7) 1 1 1 1 1 1 fd1026 fd1026 fd1026 fd1026 fd1026 fd1026 inf inf inf inf inf inf 16916 12812 12600 17504 17504 8852 Feb Feb Feb Feb Feb Feb 15 15 15 15 15 15 18:39 18:40 18:40 18:41 18:40 18:41 libparallel.so parallel.a parallel.o sema-a sema-o sema-so Welche dynamischen Bibliotheken benutzen die Programme? ldd sema-o (oder ldd libpthread.so.1 => libc.so.1 => libdl.so.1 => libthread.so.1 => sema-a) /usr/lib/libpthread.so.1 /usr/lib/libc.so.1 /etc/lib/libdl.so.1 /usr/lib/libthread.so.1 ldd sema-so libparallel.so => libpthread.so.1 => libc.so.1 => libdl.so.1 => libthread.so.1 => /home/fd1026/.../libparallel.so /usr/lib/libpthread.so.1 /usr/lib/libc.so.1 /etc/lib/libdl.so.1 /usr/lib/libthread.so.1 Welche Pthread-Funktionen enthalten die Programme? strings sema-o | grep pthread (oder strings sema-a | grep pthread) pthread_attr_init ... strings sema-so | grep pthread Da die Pthread-Funktionen in der dynamischen Bibliothek „libparallel.so“ benutzt werden, werden sie im Programm „sema-so“ nicht gefunden. Die Optionen zum Erstellen von dynamischen Bibliotheken hängen vom C-Compiler ab. Im Programmarchiv zur Lehrveranstaltung „BG14: Betriebssysteme“ können Sie in der Datei „GNUmakefile“ sehen, wie die dynamische Bibliothek „libparallel.so“ mit verschiedenen CCompilern unter UNIX erstellt wird und in den Dateien „Makefile.bcc“ und „Makefile.mvc“ wie Hochschule Fulda, Fachbereich AI, Prof. Dr. S. Groß Praktikum zur Lehrveranstaltung Betriebssysteme Seite 3 - 6 Sie eine dynamische Bibliothek unter Microsoft Windows mit den Compilern „Borland C/C++ 5.5“ und „Microsoft Visual Studio“ erstellen. Die Datei „parallel.h“ der Lehrveranstaltung „BG14: Betriebssysteme“ enthält Datentypen, Makros und Funktionsprototypen für die Bibliothek „parallel“. Die Bibliothek stellt die Funktionen für parallele Abläufe über Threads sowie die Semaphor-Operationen „P ()“ und „V ()“ über die entsprechenden Betriebssystem-Funktionen zur Verfügung. 1) 2) 3) Datentypen für die Bibliothek parallel und die Programme zur Lehrveranstaltung semaphore Identifizierungsnummer für ein Semaphor ThrID_t Identifizierungsnummer für einen Thread PtrFunc_t Typ für einen Zeiger auf eine Funktion für die Funktion parallel ( ) Makros für die Bibliothek parallel und die Programme zur Lehrveranstaltung SLEEP (t) Thread will für t Sekunden schlafen (UNIX und Windows benutzen unterschiedliche Funktionsnamen und Basiszeiten) MAX_SEMIDS maximale Anzahl Semaphore im Programm (nur für internen Gebrauch in der Bibliothek) MAX_SEM_VALUE maximaler Wert eines Semaphors (nur für internen Gebrauch in der Bibliothek) Funktionsprototypen für die Bibliothek parallel und die Programme zur Lehrveranstaltung ThrID_t parallel (PtrFunc_t start_routine, long arg) • start_routine ist der Name einer Funktion, die parallel zu allen anderen Threads dieses Prozesses ausgeführt werden soll • arg ist ein Argument, das dem neuen Thread als Parameter übergeben wird • die Funktion liefert die ID des Threads zurück, die benutzt wird, um auf das Ende des Threads zu warten • in dieser einfachen Bibliothek können nur Funktionen ohne Rückgabewert als Thread ausgeführt werden void join_all (ThrID_t *id, int num) • id ist ein Feld von Thread-Identifizierungsnummern • num gibt die Anzahl der Einträge im Feld id an • die Funktion wartet auf das Ende aller Threads semaphore init_sem (int value) • erzeugt ein neues Semaphor und initialisiert es mit dem Wert value • value muss größer gleich 0 und kleiner gleich MAX_SEM_VALUE sein • die Funktion liefert die ID für das Semaphor zurück, die in den Funktionen P ( ) und V ( ) benutzt werden kann Hochschule Fulda, Fachbereich AI, Prof. Dr. S. Groß Praktikum zur Lehrveranstaltung Betriebssysteme Seite 3 - 7 void rel_allsem (void) gibt alle Semaphore des Prozesses frei void P (semaphore sem) Dijkstra's P-Operation für Semaphore void V (semaphore sem) Dijkstra's V-Operation für Semaphore int GetSemVal (semaphore sem) liefert den Wert eines Semaphors zurück (darf nur zum Testen des Programms benutzt werden) Das folgende Beispiel zeigt, wie die Datentypen und Funktionen zur Implementierung eines parallelen Ablaufs genutzt werden können („example.c“ im Programmarchiv zur Lehrveranstaltung „BG14: Betriebssysteme“). #include #include #include #include #define #define #define #define <stdio.h> <stdlib.h> <time.h> "parallel.h" NUM_THR NUM_CYCLES MAX_NTIME MAX_CTIME 6 30 4 2 /* /* /* /* # of # of max. max. concurrent threads normal/critical cycles time for normal work time for critical work */ */ */ */ void worker (long nr); semaphore s; int main (void) { ThrID_t thr_id [NUM_THR]; int i; /* ID's of concurrent threads /* loop variable srand ((unsigned int) time ((time_t *) NULL)); s = init_sem (1); /* create sem with value 1 /* start concurrent threads for (i = 0; i < NUM_THR; ++i) { thr_id [i] = parallel ((PtrFunc_t) worker, i); }; /* wait until all concurrent threads have terminated join_all (thr_id, NUM_THR); rel_allsem (); /* release semaphore return EXIT_SUCCESS; */ */ */ */ */ */ } void worker (long nr) { int i; /* loop variable for (i = 0; i < NUM_CYCLES; ++i) { printf ("Process %ld: doing normal work in cycle %d.\n", nr, i); /* simulate some normal work SLEEP ((unsigned int) rand () % MAX_NTIME); printf ("Process %ld: try to enter critical section in cycle " "%d.\n", nr, i); P (s); printf ("Process %ld: doing critical work in cycle %d.\n", nr, i); /* simulate some critical work SLEEP ((unsigned int) rand () % MAX_CTIME); V (s); Hochschule Fulda, Fachbereich AI, Prof. Dr. S. Groß */ */ */ Praktikum zur Lehrveranstaltung Betriebssysteme Seite 3 - 8 }; } Falls Sie das Programm auf Ihrem Rechner nicht erzeugen können, haben Sie vermutlich vergessen, dem C-Compiler das Betriebssystem auf der Kommandozeile oder in der IDE mitzuteilen. Lesen Sie ggf. den Kommentar am Anfang der Datei „parallel.h“, um das Problem zu lösen. Aufgaben 1) Übersetzen Sie das obige Programm und führen Sie es aus. Erzeugen Sie eine dynamische Bibliothek für „parallel.c“ und übersetzen Sie das Programm noch einmal mit dieser Bibliothek. Dokumentieren Sie alle Kommandos inkl. Parameter, die Sie zur Lösung dieser Aufgabe benutzt haben, in einer Datei, indem Sie die entsprechenden Zeilen aus dem Kommandozeilenfenster in die Datei kopieren. Dokumentieren Sie nur die relevanten Informationen und nicht Ihre Fehlversuche! 2) Erstellen Sie ein objektorientiertes Java-Programm, in dem mehrere Java-Threads in einer Endlos-Schleife einen individuellen Text ausgeben und dann eine Sekunde „schlafen“. Hochschule Fulda, Fachbereich AI, Prof. Dr. S. Groß