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ß