Semaphore - M. Wilhelm

Werbung
Hochschule Harz
Versuch:
fcopy
FB Automatisierung und Informatik
Betriebssysteme
Thema:
Kopieren einer Datei unter der Kontrolle von Semaphoren
Mit Java
Versuchsziele
Konzepte der parallelen Programmierung am Beispiel von Threads anwenden können.
Kenntnisse in der Implementierung von Standard Befehlen einer Kommandosprache für
Betriebssysteme zur Behandlung von Dateiein- und Dateiausgabe. Einbau von Kontrollmechanismen
mittels Semaphore.
Grundlagen
Programmieren mit mehreren Threads ist eine Form der parallelen Programmierung - eine Art des
Entwurfs und der Implementierung von parallelen Programmen. Traditionell hat eine parallele
Anwendung mehrere nebeneinander ausführbare Prozesse. Im Betrieb werden diese Prozesse von
einem Hauptprogramm erzeugt und zerstört. Die Prozesse müssen zusammenarbeiten und teilen
Daten miteinander.
Überblick
Erstellen Sie ein Programm in Java zum Kopieren einer Datei in eine andere Datei. Werten Sie dazu
das in der Vorlesung vorgestellte Programm Filecopy.java aus (s.Anhang). Es sollten mindestens vier
Argumente pro Konstruktor berücksichtigt werden.
Anders als Filecopy soll ein Erzeuger-Thread die Daten von der Datei lesen und in einen Puffer
schreiben, falls dieser “leer” ist. Der Puffer wird durch einen Verbraucher-Thread „geleert” und in die
Zieldatei geschrieben. Damit können beispielsweise unterschiedliche Anforderungen beim Lesen von
einer (langsamen) Diskette und Schreiben auf eine (schnelle) Festplatte besser berücksichtigt werden,
d.h. die Datei auf der Diskette wird sofort nach dem Füllen des Puffers wieder gelesen.
Tipp: Die Synchronisation soll mittels Semaphore realisiert werden.
Folgender Ablauf soll realisiert werden:
voll/
leer
Erzeuger
Quelldatei
Verbraucher
Puffer
Zieldatei
Die Synchronisation geschieht durch zwei Semaphore, voll und leer. Dieser stellen sicher, dass
während des Beschreibens des Puffers der Verbraucher nicht bereits (Teil-) Daten entfernt. Dies ist ein
“kritischer Bereich”. Wenn der Puffer voll ist, wird dieser Zustand in den Semaphoren vermerkt.
1
Aufgabe
Abbildung 1 Musterlösung
In Aufgabe1.java sollen folgende Funktionalitäten integriert werden:
• Im OnClick-Event werden folgende Daten erzeugt:
o Thread Erzeuger
o Thread Verbraucher
o Die Semaphore müssen an die Threads übergeben werden
o Die Variablen „Buffer“, „n“ und „data“ müsssen als eine Instanz an die Threads
übergeben werden
o Die Klasse „myThread“ darf keine innere Klasse sein
o Für den Reader und den Writer soll jeweils eine Klasse erstellt werden
• Beide Prozesse sollen je nach Aufgabe ein Read-Handle oder ein Write-Handle für die Quellbzw. Zieldatei anlegen und damit das Schreiben in bzw. Lesen aus dem Puffer realisieren
• Beide Prozesse sollen in der run-Methode je nach Aufgabe die readBytes() bzw. writeBytes()
Methode aufrufen
• Beide Prozesse sollen nach dem Lesen/Schreiben in der run-Methode pausieren (die
Pausendauer soll bei der Prozesserzeugung mittels der Variablen „pause“ übergeben werden)
• Beide Prozesse benötigen zum gemeinsamen Arbeiten dieselben (!) Variablen
o int _n=0;
// Anzahl der gelesenen / zu schreibenden Bytes
o byte _data[] = new byte[512]; // Puffer (auch ein Vielfaches ist möglich)
o Die zu kopierende Datei muss aber größer als der Puffer sein
• Alle Versuche (down) sollen im Editor mit protokolliert werden
Hinweise:
• Globale Klassenvariabeln beginnen in BS-Laboren mit einem Unterstrich
• Die Semaphore müssen außerhalb der Thread-Klasse erzeugt werden.
Vor Beginn ist zu Überlegen, welche Teile wie oft aufgerufen werden müssen (Stichwort Schleife) und
wo und wie die Variablen und Methoden zu deklarieren sind (Stichwort Gültigkeitsbereich)!
2
Bausteine
-
-
try-catch für Handles, Lese- und Schreibprozesse (zum Abfangen von Fehlern !)
try {
…
}
catch (IOExeception io) {
System.out.println(„IOException“)
}
try-catch für Semaphore
try {
…
}
catch (InterruptedException e) {
System.out.println(„InterruptedException e “)
}
-
Lese-Handle
FileInputStream src = new FileInputStream(String der Quelladresse);
-
Schreib-Handle
FileOutputStream dest = new FileOutputStream(String der Zieladresse);
-
Einlese-Funktion
n = src.read(Puffer); // n: Anzahl der gelesenen Bytes; bei EndOfFile -> n=-1 (!)
-
Schreibe-Methode
dest.write(Puffer, Start-Pos. im Array, Anzahl der zu schreibenden Bytes);
-
Pause
Thread.sleep(Dauer);
-
Semaphore
Semaphore sem = new Semaphore (Anzahl, true);
sem.acquire();
sem.release();
3
Überblick für die Klasse Erzeuger:
public class ErzeugerThread ????? {
// Variablendefinition fehlen noch
public ErzeugerThread (Semaphore sem, Param param) {
// hier fehlt noch Code, auch im Parameter (Editor)
} // Constructor
public void readBytes() {
// check, ob Puffer leer ?
try {
// lesen
}
catch (InterruptedException ie) {
System.out.println("InterruptedException");
}
} // readBytes
public void run(){
do{
try {
sleep(_pause);
// Versuch zu kopieren
readBytes();
} catch (InterruptedException e) { }
} while(!_ende);
System.out.println("Ende Erzeuger ");
} // run
4
Überblick für die Klasse Verbraucher:
public class VerbraucherThread ????? {
// Variablendefinition fehlen noch
public VerbraucherThread (Semaphore sem, Param param) {
// hier fehlt noch Code, auch im Parameter (Editor)
} // Constructor
public void writeBytes() {
// check, ob Puffer voll?
try {
// schreiben
}
catch (IOException io) {
System.out.println("IOException");
}
} // writeBytes
public void run(){
do{
try {
sleep(_pause);
// Versuch zu kopieren
writeBytes();
} catch (InterruptedException e) { }
} while(!_ende);
System.out.println("Ende Verbraucher ");
} // run
5
Beispielcode aus der Vorlesung zum Kopieren einer Datei
Folgendes Programm kopiert eine Datei in eine andere ohne Threads zu verwenden.
import java.io.*;
public class Filecopy {
byte data[];
public static void main(String args[]){
String sQuelle = "test1.txt";
String sZiel = "test2.txt";
try {
data = new byte[512];
FileInputStream src = new FileInputStream(sQuelle);
FileOutputStream dest = new FileOutputStream(sZiel);
int n;
do {
n = src.read(data);
if (n > 0) dest.write(data,0, n);
} while (n > 0);
// n = -1 falls end of file erreicht
}
catch (IOException io) {
System.out.println("IOException"); }
}
}
Erläuterung:
FileInputStream
FileOutputStream
n = src.read(data);
Dest.write(data,0,n);
Verwaltet das Einlesen aus einer Datei
Verwaltet das Schreiben in eine Datei
Versucht 512 Byte zu lesen. Rückgabewert ist die Anzahl der eingelesen
Bytes.
Die Meldung EOF wird mit dem Rückgabewert -1 realisiert.
Versucht n Byte aus den Array „data“ in die Datei zu schreiben
0 ist die Anfangsposition im Array.
Umwandeln der Eingangswerte eines JSpinner`s
int pause1;
int pause2;
Integer I;
I = (Integer) spinner.getValue();
pause1 = I.intValue();
// Umwandeln nach einem Integer-Objekt
// holen des int-Werts
6
Semaphore
Semaphore sind ab dem JDK 1, 5 in Java implementiert.
Package:
import java.util.concurrent.Semaphore;
Konstruktor:
Semaphore(int permits, boolean fair);
Methoden Down:
public void acquire() throws InterruptedException;
public void acquire(int permits) throws InterruptedException;
Methoden Up:
public void release() throws InterruptedException;
public void release(int permits) throws InterruptedException;
Beispiel:
// Erzeugt fünf Thread, die über ein Semaphore gesteuert werden.
// Jeweils zwei Thread können gleichzeitig in den kritischen Bereich eintreten.
public void test() {
Semaphore sem;
sem = new Semaphore(2,true), // Semaphore erzeugt
myThread t1 = myThread(sem);
myThread t2 = myThread(sem);
myThread t3 = myThread(sem);
myThread t4 = myThread(sem);
myThread t5 = myThread(sem);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
// Threadklasse
class myThread{
Semaphore sem;
public myThread(Semaphore sem) {
this.sem = sem;
}
public void run(){
while (true) {
sem. acquire();
// some work
sem.release();
}
}
// down
// up
}
7
Herunterladen