This commit is contained in:
stsh
2022-02-17 11:32:44 +01:00
parent 0765adb9ed
commit 91762d5c9d
192 changed files with 10451 additions and 0 deletions
+242
View File
@@ -0,0 +1,242 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<diagram program="umlet" version="14.3.0">
<zoom_level>10</zoom_level>
<element>
<id>UMLClass</id>
<coordinates>
<x>90</x>
<y>370</y>
<w>200</w>
<h>200</h>
</coordinates>
<panel_attributes>lt=..
*Kaffee-Automat*</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>90</x>
<y>690</y>
<w>150</w>
<h>110</h>
</coordinates>
<panel_attributes>while (1) {
...
sem_wait(coin);
sem_post(coffee);
...
}
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>420</x>
<y>690</y>
<w>150</w>
<h>110</h>
</coordinates>
<panel_attributes>while (1) {
...
sem_post(coin);
sem_wait(coffee);
...
}
style=wordwrap</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>230</x>
<y>710</y>
<w>200</w>
<h>40</h>
</coordinates>
<panel_attributes>lt=&lt;.
coin</panel_attributes>
<additional_attributes>10.0;20.0;180.0;20.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>230</x>
<y>730</y>
<w>200</w>
<h>40</h>
</coordinates>
<panel_attributes>lt=&lt;.
coffee</panel_attributes>
<additional_attributes>180.0;20.0;10.0;20.0</additional_attributes>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>130</x>
<y>430</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>auf Geld warten</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>130</x>
<y>490</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>Kaffee ausgeben</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>180</x>
<y>390</y>
<w>30</w>
<h>60</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;40.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>180</x>
<y>450</y>
<w>30</w>
<h>60</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;40.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>180</x>
<y>510</y>
<w>30</w>
<h>60</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;40.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>100</x>
<y>400</y>
<w>110</w>
<h>150</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>90.0;10.0;10.0;10.0;10.0;130.0;90.0;130.0</additional_attributes>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>380</x>
<y>370</y>
<w>200</w>
<h>200</h>
</coordinates>
<panel_attributes>lt=..
*Kunde*</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>420</x>
<y>430</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>Geld einwerfen</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>UMLClass</id>
<coordinates>
<x>420</x>
<y>490</y>
<w>120</w>
<h>30</h>
</coordinates>
<panel_attributes>auf Kaffee warten</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>390</y>
<w>30</w>
<h>60</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;40.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>450</y>
<w>30</w>
<h>60</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;40.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>510</y>
<w>30</w>
<h>60</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;40.0;10.0;10.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>470</x>
<y>400</y>
<w>110</w>
<h>150</h>
</coordinates>
<panel_attributes>lt=&lt;-</panel_attributes>
<additional_attributes>10.0;10.0;90.0;10.0;90.0;130.0;10.0;130.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>240</x>
<y>430</y>
<w>200</w>
<h>40</h>
</coordinates>
<panel_attributes>lt=&lt;.
coin</panel_attributes>
<additional_attributes>10.0;20.0;180.0;20.0</additional_attributes>
</element>
<element>
<id>Relation</id>
<coordinates>
<x>240</x>
<y>490</y>
<w>200</w>
<h>40</h>
</coordinates>
<panel_attributes>lt=&lt;.
coffee</panel_attributes>
<additional_attributes>180.0;20.0;10.0;20.0</additional_attributes>
</element>
</diagram>
Binary file not shown.
Binary file not shown.
+187
View File
@@ -0,0 +1,187 @@
# 08 - Synchronisationsprobleme
___
## 1. Übersicht
![](./synchronisationsprobleme.png)
[Quelle: https://commons.wikimedia.org/wiki/File:Velgast-suedbahn.jpg](https://commons.wikimedia.org/wiki/File:Velgast-suedbahn.jpg)
In diesem Praktikum lernen sie zuerst am Beispiel eines Kaffee-Automaten verschiedene grundlegende Synchronisationsprobleme kennen und mit Hilfe von Locks (Mutexes) und Semaphoren lösen:
- gegenseitiger Ausschluss mit einem Lock
- Erzwingen einer einfachen Reihenfolge
- Erzwingen einer erweiterten Reihenfolge
Im zweiten Teil werden sie auf Basis dieser Grundlagen ein komplexeres Synchronisationsproblem bearbeiten, diesmal am Beispiel von Bank Transaktionen.
___
### 1.1 Nachweis
Dieses Praktikum ist eine leicht abgewandelte Variante des Sync Praktikum des Moduls BSY, angepasst an die Verhältnisse des SNP Moduls. Die Beispiele und Beschreibungen wurden, wo möglich, eins-zu-ein übernommen.
Als Autor des BSY Praktikums ist genannt: M. Thaler.
___
## 2. Lernziele
In diesem Praktikum werden sie Synchronisationsprobleme lösen
- Sie wissen wie man systematisch Synchronisationsprobleme analysiert
- Sie wissen wann ein potentieller Deadlock entstehen kann
- Sie können Mutex mit Threads anwenden
- Sie können Semaphoren mit Prozessen anwenden
___
## 3. Einführung
Das Lösen von Synchronisationsproblemen ist oft nicht einfach, weil Prozesse bzw. Threads gleichzeitig ablaufen, ihre Aktivitäten jedoch nach Vorgaben koordiniert werden müssen: man verliert schnell den Überblick. Systematisches Vorgehen mit Aufzeichnen der Abläufe und Synchronisationsbedingungen bewährt ich sich in diesem Fall.
___
### 3.1 Wie löst man Synchronisationsprobleme?
Gehen sie beim Lösen von Synchronisationsproblemen in folgenden Schritten vor:
- **Schritt 1: Prozesse (Threads) der Problemstellung identifizieren.**
Prozesse sind die Aktivitäten, die gleichzeitig ausgeführt werden. In diesem Sinne sind sie eigenständige Ausführungs-Einheiten, deren zeitliches Verhalten synchronisiert werden muss.
- **Schritt 2: Ausführungsschritte der einzelnen Prozesse (Threads) ermitteln.**
Erstellen sie eine Liste mit einer Spalte für jeden Prozess. Notieren sie für jeden Prozess stichwortartig die wesentlichen Aktionen in der gewünschten zeitlichen Reihenfolge. Tragen sie noch keine Synchronisationsoperationen ein, sondern Texte wie warten auf Geld, etc. Übertragen sie anschliessend die Liste in einen Ablaufgraphen (Siehe Beispiel in Abbildung 1).
- **Schritt 3: Synchronisationsbedingungen ermitteln.**
Eine Synchronisationsbedingung ist eine zeitliche Beziehung (Abhängigkeit) zwischen Aktionen verschiedener Prozesse, die für das korrekte Arbeiten erforderlich ist. Zeichnen sie diese Beziehungen mit Pfeilen in den Ablaufgraphen aus Schritt 2 ein (Siehe Abbildung 1).
- **Schritt 4: Benötigte Semaphore definieren.**
Für jede Synchronisationsbedingung wird ein eigener Semaphor benötigt. Notieren sie für jeden Semaphor einen Namen und den Wert, mit dem er initialisiert werden muss.
- **Schritt 5: Prozesse mit Semaphore Operationen ergänzen.**
Erweitern sie nun alle Prozesse aus Schritt 2 mit den notwendigen Semaphore Operati-onen (Siehe Pseudocode in Abbildung 1).
- **Schritt 6: Implementation.**
Implementieren und testen sie das vollständige Programm.
![](./coffee_customer.png)
```c
coin = sem_open(...,0);
coffee = sem_open(...,0);
```
Ablaufgraph und Pseudocode für 2 Prozesse und zwei Semaphore
![](./sequence_graph.png)
## 4. Der Kaffee-Automat
Als Beispiel verwenden wir einen Automaten, der Kaffee verkauft. Der Kunde muss zum Kauf eines Kaffees zuerst eine bzw. mehrere Münzen einwerfen und anschliessend den gewünsch-ten Kaffee wählen. Der Automat gibt dann das entsprechende Getränk aus.
Im ersten Beispiel werden der Automat und die Kunden mit Threads modelliert und tauschen Daten über gemeinsame Speichervariablen aus. Im zweiten und dritten Beispiel werden der Automat und die Kunden mit Prozessen modelliert, dabei wird der Ablauf mit Hilfe von Sema-phoren gesteuert bzw. erzwungen.
**Hinweis:** die Programme zu den folgenden Aufgaben können alle mit **startApp.e** gestartet werden. Dieses Programm startet und stoppt Threads und Prozesse, alloziert und dealloziert die Ressourcen (Mutexes, Semaphore).
___
### 4.1 Aufgabe: Mutual Exclusion
Greifen mehrere Threads (oder Prozesse) auf gemeinsame Daten zu, können sogenannte Race Conditions entstehen. Das Resultat ist in diesem Fall abhängig von der Reihenfolge, in der die Threads (Prozesse) ausgeführt werden.
Im vorliegenden Beispiel wirft der Kunde eine 1 Euro Münze ein und drückt anschliessend auf eine von zwei Kaffeewahltasten. Dabei wird die Anzahl Münzen (*coinCount*) und die gewählte Kaffeesorte (*selCount1*, *selCount2*) inkrementiert. Diese Variablen sind in der Datenstruktur *cData* abgelegt, auf die gemeinsam Kaffee-Automat und Kunden zugreifen können. Der Auto-mat überprüft, ob die Anzahl Münzen und die Anzahl der Kaffeewahlen gleich gross sind, falls nicht, wird eine Fehlermeldung ausgegeben und alle Zähler auf *Null* gesetzt.
#### Aufgaben
1. Übersetzen sie die Programme im Verzeichnis *mutex* mit *make* und starten sie den Kaffee-Automaten mit **startApp.e** mehrmals hintereinander.
Analysieren sie die Datenwerte in den Fehlermeldungen, beschreiben sie was die Gründe dafür sind bzw. sein können.
2. Schützen sie nun den Zugriff auf die gemeinsamen Daten mit einem Mutex so, dass alle Threads eine konsistente Sicht der Daten haben.
Wir haben für sie einen Mutex vorbereitet: die Datenstruktur *cData* enthält die Mutex-Variable *mutex*, die in **startApp.c** initialisiert wird. Die Funktionen für das Schliessen und das Öffnen des Mutex (Locks) aus der *pthread* Bibliothek sind:
```c
pthread mutex lock(&(cD->lock));
```
- und
```c
pthread mutex unlock(&(cD->lock));
```
Überprüfen sie, ob der Kaffee-Automat nun keine Fehlermeldungen mehr ausgibt. Erhö-hen sie dazu auch die Anzahl Kunden *CUSTOMERS* in **commonDefs.h**, z.B. auf 10.
3. Im Thread des Kaffee-Automaten wird an verschiedenen Orten mehrmals auf die gemeinsamen Daten in *cD* zugegriffen. Wenn sie die gemeinsamen Daten in lokale Variablen kopieren und dann nur noch auf diese lokalen Variablen zugreifen würden, könn-ten sie dann auf die Synchronisation mit dem Mutex verzichten?
4. Wie oft kann ein einzelner Kunde einen Kaffee beziehen, bis der nächste Kunde an die Reihe kommt? Hier reicht eine qualitative Aussage.
### 4.2 Aufgabe: Einfache Reihenfolge
Wie sie im ersten Beispiel festgestellt haben, verhindert ein Mutex zwar, dass Race Conditions auftreten, die Verarbeitungsreihenfolge der Threads lässt sich jedoch nicht beeinflussen und ist zufällig.
Im Folgenden soll eine erzwungene Verarbeitungsreihenfolge implementiert werden:
- Ein Kunde benutzt den Automat für einen Kaffeekauf exklusiv, d.h. alle Schritte des Kunden werden innerhalb eines Mutexes ausgeführt. Ist ein Kunde an der Reihe, wartet er bis der Automat bereit ist, wirft eine Münze ein, wartet auf den Kaffee und gibt anschlies-send den Automaten für den nächsten Kunden frei.
- Der Automat meldet zuerst in einer Endlos-Schleife, dass er für die Geld-Eingabe bereit ist, wartet dann auf die Eingabe einer Münze, gibt den Kaffee aus und meldet anschliessend wieder, wenn er bereit ist, etc.
Für die Lösung dieses Problems benötigen wir Semaphore, die, im Gegensatz zu Mutexes, auch in verschiedenen Prozessen gesetzt bzw. zurückgesetzt werden dürfen. Den Kaffee-Automat und die Kunden implementieren wir mit Prozessen. sie finden die entsprechenden Prozesse im Verzeichnis **basicSequence**.
#### Aufgaben
1. Beschreiben sie den Kaffee-Automaten mit Hilfe der 6 Schritte aus Abschnitt 3 auf Papier, dokumentieren sie dabei alle Schritte schriftlich.
2. Implementieren sie nun den Kaffee-Automaten. Ergänzen sie dazu den *coffeeTeller* und den *customer* Prozess so mit vier Semaphoren, dass die vorgegebenen Ablaufbedingungen eingehalten werden. Mit welchen Werten müssen die Semaphore initialisiert werden?
Wir haben für sie vier Semaphore vorbereitet: Achtung, sie sind aber noch auskommentiert (siehe commonDefs.h und startApp.c. Die benötigten Semaphor-Funktionen aus der POSIX Bibliothek sind:
```c
sem_wait(&semaphor);
```
und
```c
sem_post(&semaphor);
```
Analysieren sie die Ausgabe der Prozesse (mehrmals starten). Was fällt auf?
3. Gibt Ihr Programm den Output in der korrekten Reihenfolge aus? Falls nicht, wie könnte das gelöst werden?
### 4.3 Aufgabe: Erweiterte Reihenfolge
Die Preise steigen dauernd ... auch der Kaffee wird immer teurer, er kostet nun 3 Euro. Da der Automat nur 1 Euro Stücke annehmen kann, muss der Kunde 3 Münzen einwerfen. Erweitern sie die Prozesse aus Aufgabe 4.2 so, dass eine vordefinierte Anzahl Münzen eingegeben werden muss (die Anzahl Münzen ist in *commonDefs.h* als *NUM_COINS* definiert). Verwenden sie keine zusätzlichen Semaphore, sondern nutzen sie, dass wir Counting Semaphore verwenden. Die vordefinierten Prozesse finden sie im Verzeichnis *advancedSequence*.
#### Aufgabe
- Passen sie den coffeeTeller und den customer Prozess so an, dass der Kunde mehrere Münzen einwerfen muss, bis der Automat einen Kaffee ausgeben kann.
**Hinweis:** POSIX Semaphore sind Counting Semaphore, können aber nicht auf vordefinierte Werte gesetzt werden (ausser bei der Initialisierung). Abhilfe schafft hier das mehrmalige Aufrufen von *sem_post()*, z.B. in einer for-Schleife.
### 4.4 Zusammenfassung
Wir haben drei grundlegenden Typen von Synchronisationsproblemen kennen gelernt:
- **Mutex** nur ein Prozess bzw. Thread kann gleichzeitig auf gemeinsame Daten zugreifen.
- Beispiel: entweder liest der Kaffee-Automat die Daten oder ein Kunde verändert sie.
- **Einfache Reihenfolge** ein Prozess wartet auf die Freigabe durch einen anderen Prozess.
- Beispiel: der Kaffee-Automat wartet auf die Eingabe einer Münze.
- **Erweiterte Reihenfolge** ein Prozess wartet auf mehrere Freigaben durch einen anderen Pro-zess.
- Beispiel: der Kaffee-Automat wartet auf die Eingabe von drei Münzen.
___
## 5. International Banking
Die International Bank of Transfer (IBT) besitzt in 128 Ländern Filialen und stellt für 2048 spezielle Handels-Kunden in jeder Filiale ein Konto zur Verfügung. Gelder dieser Kunden werden dauernd zwischen den Filialen hin und her transferiert, dazu beschäftigt die Bank sogenannte Pusher. Pusher heben Geldbeträge von Konten in einer Filiale ab und buchen sie auf den entsprechenden Konten in irgendeiner (auch in der eigenen) Filiale wieder ein. Die Beträge liegen zwischen 1000 und 100000 Dollar und werden zufällig ausgewählt, die Wahl der beiden Filialen ist ebenfalls zufällig.
### 5.1 Implementation
Im Folgenden arbeiten wir mit einer *pthread*-basierten Implementation der IBT, die Pusher werden dabei mit Threads implementiert. Die Filialen der Bank sind als Array von Strukturen implementiert, wobei pro Filiale ein Lock (*branchLock*) und ein Array von Konten (Accounts) definiert ist. Die Konten sind wiederum Strukturen mit dem Kontostand (*account*) und dem Lock (*acntLock*), siehe dazu auch den Source Code. Die Zugriffe auf die Gelder sind imple-mentiert (Funktionen *withdraw()*, *deposit()*, *transfer()*), aber nicht synchronisiert.
**Hinweis:** es ist von Vorteil hier mit mehreren CPUs zu arbeiten. Falls sie eine VM verwenden, setzen sie die Anzahl CPUs auf das Maximum.
### 5.2 Aufgabe: Konto Synchronisation
1. Wechseln sie ins Verzeichnis **banking/a1**, übersetzen sie das Programm und starten sie es mit dem Skript `./startApp`. Analysieren und erklären sie die Resultate. Notie-ren sie sich zudem die Laufzeiten für 1, 2 und 4 Threads.
2. Synchronisieren sie die Kontenzugriffe so, dass möglichst viele Zugriffe gleichzeitig ausgeführt werden können und die Zugriffe atomar sind. Sie dürfen nur eines der beiden Locks *branchLock* bzw. *acntLock* verwenden: welches wählen sie und wieso? Be-gründen sie ihre Antwort und testen sie ihre Lösung.
### 5.3 Aufgabe: Filialen Zugriff in Critical Section
Ihr Chef meint, dass es wohl aus Sicherheitsgründen besser wäre, sowohl die Filialen und die jeweiligen Kontenzugriffen zu ”locken”.
1. Wechseln sie ins Verzeichnis banking/a2 und kopieren sie banking.c aus Aufgabe 5.2. Implementieren sie diese zusätzlichen Anforderungen. Analysieren sie die Resultate. Was stellen sie fest im Vergleich mit den Resultaten aus der Aufgabe 5.2? Was raten sie ihrem Chef?
2. Ein Kollege meint, es wäre effizienter beim Abheben des Betrags zuerst das Konto zu locken und dann die Filiale, hingegen beim Einbuchen zuerst die die Filiale und dann das Konto. Was für eine Antwort geben sie ihrem Kollegen?**Hinweis:** falls sie nicht sicher sind: probieren sie es aus.
### 5.4 Aufgabe: Refactoring der Synchronisation
Das International Banking Committe (IBC) erlässt neue Richtlinien, die unter anderem fordern, dass die Gesamtbilanz einer Bank über sämtliche Filialen zu jeder Zeit konsistent sein muss.
1. Erklären sie wieso die Implementationen aus Aufgabe 5.2 und 5.3 diese Anforderungen nicht erfüllen.
2. Ihr Entwicklungsteam kommt zum Schluss, dass den Pushern neu nur noch eine Funktion *transfer()* für die Überweisung von Beträgen zwischen den Filialen und Konten zur Verfügung gestellt werden darf.
Welche Locks bzw. welches Lock muss verwendet werden, damit die Forderung des IBC erfüllt werden kann? Wechseln sie ins Verzeichnis *banking/a3* und ergänzen sie die Funktion *transfer()* in banking.c um die entsprechenden Lock-Funktionen.
Wichtiger
**Hinweis:** es darf kein neues Lock eingeführt werden und die Gesamtbilanz über sämtliche Filialen muss jederzeit konsistent sein.
3. Testen und analysieren sie das Programm und vergleichen sie die Resultate (Funktionalität, Laufzeit) mit den Lösungen aus Aufgabe 5.2 und 5.3. Notieren sie sich, was ihnen bei dieser Aufgabe wichtig erscheint.
4.
___
## 6. Bewertung
Die gegebenenfalls gestellten Theorieaufgaben und der funktionierende Programmcode müssen der Praktikumsbetreuung gezeigt werden. Die Lösungen müssen mündlich erklärt werden.
| Aufgabe | Kriterium | Gewicht |
| :-- | :-- | :-- |
| | Sie können die gestellten Fragen erklären. | |
| 4 | 4.1 Aufgabe: Mutual Exclusion<br>4.2 Aufgabe: Einfache Reihenfolge<br>4.3 Aufgabe: Erweiterte Reihenfolge | 4 |
| 5 | 5.2 Aufgabe: Konto Synchronisation<br>5.3 Aufgabe: Filialen Zugriff in Critical Section<br>5.4 Aufgabe: Refactoring der Synchronisation | 4 |
___
___
Version: 18.08.2021
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

+129
View File
@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN'
'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>
<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="530" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="70 350 530 240" height="240" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto"
><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs"
/><g
><defs id="defs1"
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1"
><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2"
><path d="M0 0 L0 30 L120 30 L120 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3"
><path d="M0 0 L0 200 L200 200 L200 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4"
><path d="M0 0 L0 40 L200 40 L200 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5"
><path d="M0 0 L0 150 L110 150 L110 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6"
><path d="M0 0 L0 60 L30 60 L30 0 Z"
/></clipPath
></defs
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(420,490)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath2)" stroke="none"
/></g
><g transform="translate(420,490)"
><rect fill="none" x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath2)"
/><text x="5" font-size="14px" y="17.9688" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
>auf Kaffee warten</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(420,430)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath2)" stroke="none"
/></g
><g transform="translate(420,430)"
><rect fill="none" x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath2)"
/><text x="12" font-size="14px" y="17.9688" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Geld einwerfen</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(380,370)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="198.5" height="198.5" y="0.5" clip-path="url(#clipPath3)" stroke="none"
/></g
><g stroke-dasharray="1,2" stroke-miterlimit="5" transform="translate(380,370)" stroke-linecap="butt"
><rect fill="none" x="0.5" width="198.5" height="198.5" y="0.5" clip-path="url(#clipPath3)"
/><text x="78" font-size="14px" y="17.9688" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" font-weight="bold" xml:space="preserve"
>Kunde</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(130,490)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath2)" stroke="none"
/></g
><g transform="translate(130,490)"
><rect fill="none" x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath2)"
/><text x="7" font-size="14px" y="17.9688" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
>Kaffee ausgeben</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(130,430)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath2)" stroke="none"
/></g
><g transform="translate(130,430)"
><rect fill="none" x="0.5" width="118.5" height="28.5" y="0.5" clip-path="url(#clipPath2)"
/><text x="10" font-size="14px" y="17.9688" clip-path="url(#clipPath2)" font-family="sans-serif" stroke="none" xml:space="preserve"
>auf Geld warten</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(90,370)" stroke-opacity="0" stroke="rgb(255,255,255)"
><rect x="0.5" width="198.5" height="198.5" y="0.5" clip-path="url(#clipPath3)" stroke="none"
/></g
><g stroke-dasharray="1,2" stroke-miterlimit="5" transform="translate(90,370)" stroke-linecap="butt"
><rect fill="none" x="0.5" width="198.5" height="198.5" y="0.5" clip-path="url(#clipPath3)"
/><text x="47" font-size="14px" y="17.9688" clip-path="url(#clipPath3)" font-family="sans-serif" stroke="none" font-weight="bold" xml:space="preserve"
>Kaffee-Automat</text
></g
><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(240,490)" stroke-linecap="butt"
><path fill="none" d="M179.5 20.5 L10.5 20.5" clip-path="url(#clipPath4)"
/><path fill="none" stroke-miterlimit="10" stroke-dasharray="none" d="M168.7417 14 L180 20.5 L168.7417 27" clip-path="url(#clipPath4)" stroke-linecap="square"
/></g
><g font-family="sans-serif" font-size="14px" transform="translate(240,490)"
><text x="75.9312" xml:space="preserve" y="16" clip-path="url(#clipPath4)" stroke="none"
>coffee</text
></g
><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(240,430)" stroke-linecap="butt"
><path fill="none" d="M11.5 20.5 L180.5 20.5" clip-path="url(#clipPath4)"
/><path fill="none" stroke-miterlimit="10" stroke-dasharray="none" d="M22.2583 27 L11 20.5 L22.2583 14" clip-path="url(#clipPath4)" stroke-linecap="square"
/></g
><g font-family="sans-serif" font-size="14px" transform="translate(240,430)"
><text x="82.1587" xml:space="preserve" y="16" clip-path="url(#clipPath4)" stroke="none"
>coin</text
></g
><g transform="translate(470,400)"
><path fill="none" d="M11.5 10.5 L90.5 10.5" clip-path="url(#clipPath5)"
/><path fill="none" d="M90.5 10.5 L90.5 130.5" clip-path="url(#clipPath5)"
/><path fill="none" d="M90.5 130.5 L10.5 130.5" clip-path="url(#clipPath5)"
/><path fill="none" d="M22.2583 17 L11 10.5 L22.2583 4" clip-path="url(#clipPath5)"
/></g
><g transform="translate(470,510)"
><path fill="none" d="M10.5 39.5 L10.5 10.5" clip-path="url(#clipPath6)"
/><path fill="none" d="M17 28.7417 L10.5 40 L4 28.7417" clip-path="url(#clipPath6)"
/></g
><g transform="translate(470,450)"
><path fill="none" d="M10.5 39.5 L10.5 10.5" clip-path="url(#clipPath6)"
/><path fill="none" d="M17 28.7417 L10.5 40 L4 28.7417" clip-path="url(#clipPath6)"
/></g
><g transform="translate(470,390)"
><path fill="none" d="M10.5 39.5 L10.5 10.5" clip-path="url(#clipPath6)"
/><path fill="none" d="M17 28.7417 L10.5 40 L4 28.7417" clip-path="url(#clipPath6)"
/></g
><g transform="translate(100,400)"
><path fill="none" d="M89.5 10.5 L10.5 10.5" clip-path="url(#clipPath5)"
/><path fill="none" d="M10.5 10.5 L10.5 130.5" clip-path="url(#clipPath5)"
/><path fill="none" d="M10.5 130.5 L90.5 130.5" clip-path="url(#clipPath5)"
/><path fill="none" d="M78.7417 4 L90 10.5 L78.7417 17" clip-path="url(#clipPath5)"
/></g
><g transform="translate(180,510)"
><path fill="none" d="M10.5 39.5 L10.5 10.5" clip-path="url(#clipPath6)"
/><path fill="none" d="M17 28.7417 L10.5 40 L4 28.7417" clip-path="url(#clipPath6)"
/></g
><g transform="translate(180,450)"
><path fill="none" d="M10.5 39.5 L10.5 10.5" clip-path="url(#clipPath6)"
/><path fill="none" d="M17 28.7417 L10.5 40 L4 28.7417" clip-path="url(#clipPath6)"
/></g
><g transform="translate(180,390)"
><path fill="none" d="M10.5 39.5 L10.5 10.5" clip-path="url(#clipPath6)"
/><path fill="none" d="M17 28.7417 L10.5 40 L4 28.7417" clip-path="url(#clipPath6)"
/></g
></g
></svg
>

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

+64
View File
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN'
'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>
<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="520" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="80 260 520 150" height="150" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto"
><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs"
/><g
><defs id="defs1"
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1"
><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2"
><path d="M0 0 L0 110 L150 110 L150 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3"
><path d="M0 0 L0 40 L200 40 L200 0 Z"
/></clipPath
></defs
><g font-family="sans-serif" font-size="14px" transform="translate(430,280)"
><text x="5" xml:space="preserve" y="17.9688" clip-path="url(#clipPath2)" stroke="none"
>while (1) {</text
><text x="5" xml:space="preserve" y="33.9375" clip-path="url(#clipPath2)" stroke="none"
> ...</text
><text x="5" xml:space="preserve" y="49.9062" clip-path="url(#clipPath2)" stroke="none"
> sem_post(coin);</text
><text x="5" xml:space="preserve" y="65.875" clip-path="url(#clipPath2)" stroke="none"
> sem_wait(coffee);</text
><text x="5" xml:space="preserve" y="81.8438" clip-path="url(#clipPath2)" stroke="none"
> ...</text
><text x="5" xml:space="preserve" y="97.8125" clip-path="url(#clipPath2)" stroke="none"
>}</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(100,280)"
><text x="5" xml:space="preserve" y="17.9688" clip-path="url(#clipPath2)" stroke="none"
>while (1) {</text
><text x="5" xml:space="preserve" y="33.9375" clip-path="url(#clipPath2)" stroke="none"
> ...</text
><text x="5" xml:space="preserve" y="49.9062" clip-path="url(#clipPath2)" stroke="none"
> sem_wait(coin);</text
><text x="5" xml:space="preserve" y="65.875" clip-path="url(#clipPath2)" stroke="none"
> sem_post(coffee);</text
><text x="5" xml:space="preserve" y="81.8438" clip-path="url(#clipPath2)" stroke="none"
> ...</text
><text x="5" xml:space="preserve" y="97.8125" clip-path="url(#clipPath2)" stroke="none"
>}</text
></g
><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(240,320)" stroke-linecap="butt"
><path fill="none" d="M179.5 20.5 L10.5 20.5" clip-path="url(#clipPath3)"
/><path fill="none" stroke-miterlimit="10" stroke-dasharray="none" d="M168.7417 14 L180 20.5 L168.7417 27" clip-path="url(#clipPath3)" stroke-linecap="square"
/></g
><g font-family="sans-serif" font-size="14px" transform="translate(240,320)"
><text x="75.9312" xml:space="preserve" y="16" clip-path="url(#clipPath3)" stroke="none"
>coffee</text
></g
><g stroke-dasharray="8,5" stroke-miterlimit="5" transform="translate(240,300)" stroke-linecap="butt"
><path fill="none" d="M11.5 20.5 L180.5 20.5" clip-path="url(#clipPath3)"
/><path fill="none" stroke-miterlimit="10" stroke-dasharray="none" d="M22.2583 27 L11 20.5 L22.2583 14" clip-path="url(#clipPath3)" stroke-linecap="square"
/></g
><g font-family="sans-serif" font-size="14px" transform="translate(240,300)"
><text x="82.1587" xml:space="preserve" y="16" clip-path="url(#clipPath3)" stroke="none"
>coin</text
></g
></g
></svg
>

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 182 KiB

@@ -0,0 +1,46 @@
/*******************************************************************************
* File: coffeTeller.c
* Purpose: simple sequence with semaphores
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012, 7/2013
* Version: v.fs20
*******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <semaphore.h>
#include "commonDefs.h"
//******************************************************************************
int main(void) {
int i;
sem_t *coin, *coffee, *ready;
// set up a semaphore
coin = sem_open(COIN_SEMAPHOR, 0);
coffee = sem_open(COFFEE_SEMAPHOR, 0);
ready = sem_open(READY_SEMAPHOR, 0);
// start teller machine
printf("\nCoffee teller machine starting\n\n");
i = 0;
while (i < ITERS) {
printf("teller (%d): waiting for coin\n", i);
printf(" (%d): got coin\n", i);
printf(" (%d): dispense coffee\n", i);
i++;
}
}
//******************************************************************************
@@ -0,0 +1,31 @@
#ifndef MY_DEFINITIONS_HEADER
#define MY_DEFINITIONS_HEADER
/*******************************************************************************
* File: commonDefs.h
* Purpose: common definitions
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012, 7/2013, 4/2014
* Version: v.fs20
*******************************************************************************/
#define MYTURN_SEMAPHOR "/my_semaphor_1_name_advaneced_seq"
#define COIN_SEMAPHOR "/my_semaphor_2_name_advaneced_seq"
#define COFFEE_SEMAPHOR "/my_semaphor_3_name_advaneced_seq"
#define READY_SEMAPHOR "/my_semaphor_4_name_advaneced_seq"
#define ITERS (100*1000*1000)
#define CUSTOMERS 4
#define NUM_COIN 3
//******************************************************************************
#define checkSem(X) {if (X == SEM_FAILED) {perror("sem_open"); exit(-1);}}
#define drinkingCoffee(X) {usleep((((1+X)*rand())+100000)&0xFFFFF);}
//******************************************************************************
#endif
@@ -0,0 +1,50 @@
/*******************************************************************************
* File: customer.c
* Purpose: simple sequence with semaphores
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012, 7/2013
* Version: v.fs20
*******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <semaphore.h>
#include "commonDefs.h"
//******************************************************************************
int main(int argc, char *argv[]) {
int i, myID;
sem_t *myTurn, *coin, *coffee, *ready;
if (argc > 1)
myID = atoi(argv[1]);
else
myID = 0;
// set up a semaphore
myTurn = sem_open(MYTURN_SEMAPHOR, 0);
coin = sem_open(COIN_SEMAPHOR, 0);
coffee = sem_open(COFFEE_SEMAPHOR, 0);
ready = sem_open(READY_SEMAPHOR, 0);
// start customer
printf("Customer starting (%d)\n", myID);
// now check the sum
for (i = 0; i < ITERS; i++) {
printf("\t\t\t\tcustomer(%d) put coin %d\n", myID, i);
printf("\t\t\t\tcustomer(%d) waiting for coffee %d\n", myID, i);
printf("\t\t\t\tcustomer(%d) got coffee %d\n", myID, i);
drinkingCoffee(myID);
}
}
//******************************************************************************
@@ -0,0 +1,40 @@
# BSy M. Thaler
# Version v.fs20
CMP= gcc -std=gnu99
CMPFLAGS= -Wall -g
LIB= -pthread
EXENAME0= startApp.e
EXENAME1= coffeeTeller.e
EXENAME2= customer.e
doit:
@make --no-print-directory clean
@make --no-print-directory startApp
@make --no-print-directory coffeeTeller
@make --no-print-directory customer
startApp: startApp.o
$(CMP) $(CMPFLAGS) startApp.o $(LIB) -o $(EXENAME0)
coffeeTeller: coffeeTeller.o
$(CMP) $(CMPFLAGS) coffeeTeller.o $(LIB) -o $(EXENAME1)
customer: customer.o
$(CMP) $(CMPFLAGS) customer.o $(LIB) -o $(EXENAME2)
.c.o:
$(CMP) -c $(CMPFLAGS) $<
.cc.o:
$(CMP) -c $(CMPFLAGS) $<
all:
@make clean
make doit
clean:
@rm -f *.e *.o
purge:
@make clean
@@ -0,0 +1,72 @@
/*******************************************************************************
* File: startApp.c
* Purpose: ice cream teller, basic sequence
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012, 7/2013
* Version: v.fs20
*******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <semaphore.h>
#include "commonDefs.h"
//******************************************************************************
int main(void) {
int j;
char string[8];
sem_t *access, *coin, *coffee, *ready;
pid_t tellerPID;
sem_unlink(MYTURN_SEMAPHOR); // delete seamphor if it still exists
sem_unlink(COIN_SEMAPHOR); // delete seamphor if it still exists
sem_unlink(COFFEE_SEMAPHOR); // delete seamphor if it still exists
sem_unlink(READY_SEMAPHOR); // delete seamphor if it still exists
// set up a semaphore (? -> initial value of semaphor)
// checkSem() -> macro defined in commonDefs.h
/*
access = sem_open(MYTURN_SEMAPHOR, O_CREAT, 0700, ?); checkSem(access);
coin = sem_open(COIN_SEMAPHOR, O_CREAT, 0700, ?); checkSem(coin);
coffee = sem_open(COFFEE_SEMAPHOR, O_CREAT, 0700, ?); checkSem(coffee);
ready = sem_open(READY_SEMAPHOR, O_CREAT, 0700, ?); checkSem(ready);
*/
// now that the resources are set up, the supervisor can be started
for (j = 1; j <= CUSTOMERS; j++) {
if (fork() == 0) {
sprintf(string, "%d", j);
execl("./customer.e", "customer.e", string, NULL);
printf("*** could not start customer.e ***\n");
}
}
if ((tellerPID = fork()) == 0) {
execl("./coffeeTeller.e", "coffeeTeller.e", "0", NULL);
printf("*** could not start coffeTeller ***\n");
}
waitpid(tellerPID, NULL, 0);
system("killall coffeeTeller.e");
system("killall customer.e"); // kill all customers
// clean up resources
sem_unlink(MYTURN_SEMAPHOR);
sem_unlink(COIN_SEMAPHOR);
sem_unlink(COFFEE_SEMAPHOR);
sem_unlink(READY_SEMAPHOR);
printf("\n");
}
//******************************************************************************
@@ -0,0 +1,142 @@
//******************************************************************************
// Course: BSy
// File: banking.c
// Author: M. Thaler, ZHAW
// Purpose: locking mechanisms
// Version: v.fs20
//******************************************************************************
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include "banking.h"
//******************************************************************************
#define MAX( a, b ) ( ( a > b) ? a : b )
#define MIN( a, b ) ( ( a <= b) ? a : b )
typedef struct account_struct_ {
long int balance;
pthread_mutex_t acntLock;
} Account;
typedef struct branch_struct {
Account *accounts;
pthread_mutex_t branchLock;
} Branch;
//******************************************************************************
static Branch *bank;
static int nBranches, nAccounts;
//******************************************************************************
// banking functions
void makeBank(int num_branches, int num_accounts) {
nBranches = num_branches;
nAccounts = num_accounts;
bank = (Branch *)malloc(nBranches * sizeof(Branch));
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
//pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
for (int i = 0; i < nBranches; i++) {
bank[i].accounts = (Account *)malloc(nAccounts * sizeof(Account));
for (int j = 0; j < nAccounts; j++) {
pthread_mutex_init(&bank[i].accounts[j].acntLock, NULL);
bank[i].accounts[j].balance = 0;
}
}
}
void deletebank(void) {
for (int i = 0; i < nBranches; i++)
free(bank[i].accounts);
free(bank);
nBranches = nAccounts = 0;
}
long int withdraw(int branchNr, int accountNr, long int value) {
int rv, tmp;
rv = 0;
tmp = bank[branchNr].accounts[accountNr].balance - value;
if (tmp >= 0) {
bank[branchNr].accounts[accountNr].balance = tmp;
rv = value;
};
return rv;
}
void deposit(int branchNr, int accountNr, long int value) {
bank[branchNr].accounts[accountNr].balance += value;
}
void transfer(int fromB, int toB, int accountNr, long int value) {
if (fromB == toB) {
return;
}
int first = MIN(fromB, toB);
int second = MAX(fromB, toB);
pthread_mutex_lock(&bank[first].accounts[accountNr].acntLock);
pthread_mutex_lock(&bank[second].accounts[accountNr].acntLock);
int money = withdraw(fromB, accountNr, value);
deposit(toB, accountNr, money);
pthread_mutex_unlock(&bank[first].accounts[accountNr].acntLock);
pthread_mutex_unlock(&bank[second].accounts[accountNr].acntLock);
}
void checkAssets(void) {
static long assets = 0;
long int sum = 0;
for (int i = 0; i < nBranches; i++) {
for (int j = 0; j < nAccounts; j++) {
sum += (long int)bank[i].accounts[j].balance;
}
}
if (assets == 0) {
assets = sum;
printf("Balance of accounts is: %ld\n", sum);
}
else {
if (sum != assets) {
printf("Balance of accounts is: %ld ... not correct\n", sum);
}
else
printf("Balance of accounts is: %ld ... correct\n", assets);
}
}
int checkIBC(void) {
static long ibcError = 0;
long sum = 0;
for (int i = 0; i < nBranches; i++) {
pthread_mutex_lock(&bank[i].branchLock);
for (int j = 0; j < nAccounts; j++) {
pthread_mutex_lock(&bank[i].accounts[j].acntLock);
}
}
for (int i = 0; i < nBranches; i++) {
for (int j = 0; j < nAccounts; j++) {
sum += (long)bank[i].accounts[j].balance;
}
}
for (int i = nBranches - 1; i >= 0; i--) {
pthread_mutex_unlock(&bank[i].branchLock);
for (int j = 0; j < nAccounts; j++) {
pthread_mutex_unlock(&bank[i].accounts[j].acntLock);
}
}
if (ibcError == 0) ibcError = sum;
return (ibcError != sum);
}
//******************************************************************************
@@ -0,0 +1,20 @@
//******************************************************************************
// Course: BSy
// File: banking.h
// Author: M. Thaler, ZHAW
// Purpose: locking mechanisms
// Version: v.fs20
//******************************************************************************
// banking functions
void makeBank(int num_branches, int num_accounts);
void deleteBank(void);
long withdraw(int branch, int account, long int value) ;
void deposit(int branch, int account, long int value);
void transfer(int fromB, int toB, int account, long int value);
void checkAssets(void);
int checkIBC(void);
//******************************************************************************
@@ -0,0 +1,107 @@
//******************************************************************************
// Course: BSy
// File: main.c
// Author: M. Thaler, ZHAW
// Purpose: locking mechanisms
// Version: v.fs20
//******************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "banking.h"
#include "mtimer.h"
#include "mrandom.h"
//******************************************************************************
// constant values
#define MAX_THREADS 16
#define NUM_THREADS 2
#define TRANSFERS (16*1024*1024L)
#define ACCOUNTS (2048)
#define BRANCHES (128)
//******************************************************************************
// globals
int nThreads;
int ibc = 0;
//******************************************************************************
// customers
void *pusher(void *arg) {
int idx = (int)(long)(arg);
mrand_t rand;
unsigned int seed = 17*idx;
mrandInit(seed, &rand);
int account, from, to, val;
int count = TRANSFERS / nThreads;
for (int i = 0; i < count; i++) {
account = (int)(mrandUInt(&rand) % ACCOUNTS);
from = (int)(mrandUInt(&rand) % BRANCHES);
to = (int)(mrandUInt(&rand) % BRANCHES);
val = (int)(mrandRange(1000, 100000, &rand));
transfer(from, to, account, val);
}
}
void *checker(void *arg) {
for (int i = 0; i < 1000; i = i) {
ibc += checkIBC();
usleep(100*1000);
}
}
//******************************************************************************
// main program
int main(int argc, char *argv[]) {
gtimer_t timer;
mrand_t ranvar;
long assets;
// thread id's
pthread_t th[MAX_THREADS];
// get number of threads or default
if (argc > 1)
nThreads = atoi(argv[1]);
else
nThreads = NUM_THREADS;
nThreads = (nThreads > MAX_THREADS) ? MAX_THREADS : nThreads;
mrandInit((MAX_THREADS + 1)*333, &ranvar);
printf("\nRunning %d threads\n", nThreads);
makeBank(BRANCHES, ACCOUNTS);
for (int i = 0; i < ACCOUNTS; i++)
deposit(0, i, mrandRange(10, 1000*1000, &ranvar));
checkAssets();
startGTimer(timer);
// create threads and pass thread number
pthread_create(&th[0], NULL, checker, (void *)0);
sleep(1);
for (long i = 1; i < nThreads; i++)
pthread_create(&th[i], NULL, pusher, (void *)i);
// wait for threads to terminate
for (int i = 1; i < nThreads; i++)
pthread_join(th[i], NULL);
stopGTimer(timer);
checkAssets();
printGTime(timer);
if (ibc)
printf("\n\033[41mYou do not comply with the IBC rules \033[0m\n\n");
else
printf("\n\033[42mYou do comply with the IBC rules \033[0m\n\n");
}
//******************************************************************************
@@ -0,0 +1,32 @@
# ---------------------------------------------------------------------------
# Makefile
# Course: BSy
# Date: M. Thaler, 1/2016
# File: makefile
# Version: v.fs20
# ---------------------------------------------------------------------------
#macros
CC = gcc
CFLGS = -std=gnu99
LIBS = -pthread
OFILES = main.o banking.o
HFILES = banking.h
main: $(OFILES) $(HFILES)
$(CC) $(CFLGS) $(LIBS) $(OFILES) -o $@.e
.c.o:
$(CC) $(CFLGS) -c $<
.cc.o:
$(CC) $(CFLGS) -c $<
clean:
rm -f *.o *.e
@echo "directory cleaned"
all:
@rm -f *.o
make --no-print-directory main
#-----------------------------------------------------------------------------
@@ -0,0 +1,74 @@
#ifndef MY_RANDOMGENERATOR_DEFINITIONS
#define MY_RANDOMGENERATOR_DEFINITIONS
#include <sys/time.h>
#include <assert.h>
//******************************************************************************
// Course: BSy
// File: mrandom.h
// Author: M. Thaler, ZHAW
// Purpose: thread safe random functions (reentrant)
// Version: v.fs20
//******************************************************************************
// date type: mrand_t
//
// functions:
// - void mrandInit(mrand_t *mrt) -> initialize with fixed seed
// - unsigned int mrandUInt(mrand_t *mrt) -> unsigned random number
// - unsigned int mrandRange(int low, int high, mrand_t *mrt)
// -> random number within range
//
/******************************************************************************/
// constanst for ecuyer generator: length approx 8 x 10^12
#define M1 2147483563
#define M2 2147483399
#define A1 40014
#define A2 40692
#define Q1 53668
#define Q2 52774
#define R1 12211
#define R2 3791
#define MRAND_MAX M1-1
/******************************************************************************/
typedef struct mrand_t { unsigned int s1; \
unsigned int s2; } mrand_t;
void mrandInit(unsigned int seed, mrand_t *mrt) {
mrt->s1 = 33777 + seed * 777;
mrt->s2 = 9777572 + seed * 33775;
}
unsigned int mrandUInt(mrand_t *mrt) {
unsigned int rv;
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
if (mrt->s1 <= 0) mrt->s1 += M1;
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
if (mrt->s2 <= 0) mrt->s2 += M2;
rv = (mrt->s1 + mrt->s2) % M1;
return rv;
}
double mrandDouble(mrand_t *mrt) {
unsigned int rv;
double dv;
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
if (mrt->s1 <= 0) mrt->s1 += M1;
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
if (mrt->s2 <= 0) mrt->s2 += M2;
rv = (mrt->s1 + mrt->s2) % M1;
dv = (double)rv / ((double)(M1-1));
return dv;
}
unsigned int mrandRange(unsigned int low, unsigned int high, mrand_t *mrt) {
assert(low <= high);
double drv = mrandDouble(mrt);
unsigned int av = (unsigned int)(drv * (double)(high-low) + 0.5);
return low + av;
}
/******************************************************************************/
#endif
@@ -0,0 +1,42 @@
#ifndef TIMER_MACRO_DEFINITIONS
#define TIMER_MACRO_DEFINITIONS
/******************************************************************************/
// Course: BSy
// File: mtimer.h
// Purpose: timer functions gettimeofday()
// Author: M. Thaler, ZHAW, 1/2016
// Version: v.fs20
/******************************************************************************/
// gettimeofday()
// function: elapsed time: between start and stop
// data type: gtimer_t
// functions: startGTimer(gtimer_t tdata) -> start timer
// stopGTimer(gtimer_t tdata) -> stop timer
// double getWallGTime(gtimer_t tdata) -> get time in s
// printGTime(X) -> print time in s
//
// -> see also "man gettimeofday"
/******************************************************************************/
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
/******************************************************************************/
typedef struct gtimer_t { struct timeval sT; \
struct timeval eT; } gtimer_t;
#define startGTimer(X) gettimeofday(&X.sT, NULL)
#define stopGTimer(X) gettimeofday(&X.eT, NULL)
#define getGTime(X) ((double)(X.eT.tv_sec) - (double)(X.sT.tv_sec)) +\
((double)X.eT.tv_usec - (double)X.sT.tv_usec)/1e6
#define printGTime(X) printf("Run time %3.2lfs\n", getGTime(X))
/******************************************************************************/
#endif
@@ -0,0 +1,4 @@
#!/bin/bash
./main.e 1
./main.e 2
./main.e 4
+103
View File
@@ -0,0 +1,103 @@
//******************************************************************************
// Course: BSy
// File: banking.c
// Author: M. Thaler, ZHAW
// Purpose: locking mechanisms
// Version: v.fs20
//******************************************************************************
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include "banking.h"
//******************************************************************************
typedef struct account_struct_ {
long int balance;
pthread_mutex_t acntLock;
} Account;
typedef struct branch_struct {
Account *accounts;
pthread_mutex_t branchLock;
} Branch;
//******************************************************************************
static Branch *Bank;
static int nBranches, nAccounts;
//******************************************************************************
// banking functions
void makeBank(int num_branches, int num_accounts) {
nBranches = num_branches;
nAccounts = num_accounts;
Bank = (Branch *)malloc(nBranches * sizeof(Branch));
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
for (int i = 0; i < nBranches; i++) {
Bank[i].accounts = (Account *)malloc(nAccounts * sizeof(Account));
pthread_mutex_init(&(Bank[i].branchLock), &attr);
for (int j = 0; j < nAccounts; j++) {
Bank[i].accounts[j].balance = 0;
pthread_mutex_init((&(Bank[i].accounts[j].acntLock)), &attr);
}
}
}
void deleteBank(void) {
for (int i = 0; i < nBranches; i++)
free(Bank[i].accounts);
free(Bank);
nBranches = nAccounts = 0;
}
long int withdraw(int branchNr, int accountNr, long int value) {
int rv, tmp;
rv = 0;
tmp = Bank[branchNr].accounts[accountNr].balance - value;
if (tmp >= 0) {
Bank[branchNr].accounts[accountNr].balance = tmp;
rv = value;
}
return rv;
}
void deposit(int branchNr, int accountNr, long int value) {
Bank[branchNr].accounts[accountNr].balance += value;
}
void transfer(int fromB, int toB, int accountNr, long int value) {
int money = withdraw(fromB, accountNr, value);
if (money >= 0)
deposit(toB, accountNr, money);
}
void checkAssets(void) {
static long assets = 0;
long sum = 0;
for (int i = 0; i < nBranches; i++) {
for (int j = 0; j < nAccounts; j++) {
sum += (long)Bank[i].accounts[j].balance;
}
}
if (assets == 0) {
assets = sum;
printf("Balance of accounts is: %ld\n", sum);
}
else {
if (sum != assets)
printf("Balance of accounts is: %ld ... not correct\n", sum);
else
printf("Balance of accounts is: %ld ... correct\n", assets);
}
}
//******************************************************************************
+19
View File
@@ -0,0 +1,19 @@
//******************************************************************************
// Course: BSy
// File: banking.h
// Author: M. Thaler, ZHAW
// Purpose: locking mechanisms
// Version: v.fs20
//******************************************************************************
// banking functions
void makeBank(int num_branches, int num_accounts);
void deleteBank(void);
long int withdraw(int branchNr, int accountNr, long int value) ;
void deposit(int branchNr, int accountNr, long int value);
void transfer(int fromB, int toB, int accountNr, long int value);
void checkAssets(void);
//******************************************************************************
+93
View File
@@ -0,0 +1,93 @@
//******************************************************************************
// Course: BSy
// File: main.c
// Author: M. Thaler, ZHAW
// Purpose: locking mechanisms
// Version: v.fs20
//******************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "banking.h"
#include "mtimer.h"
#include "mrandom.h"
//******************************************************************************
// constant values
#define MAX_THREADS 16
#define NUM_THREADS 4
#define TRANSFERS (16*1024*1024)
#define ACCOUNTS (2048)
#define BRANCHES (128)
//******************************************************************************
// globals
int nThreads;
//******************************************************************************
// pusher
void *pusher(void *arg) {
int idx = (int)(long)(arg);
mrand_t rand;
unsigned int seed = 17*idx;
mrandInit(seed, &rand);
int account, from, to, val;
int count = TRANSFERS / nThreads;
for (int i = 0; i < count; i++) {
account = (int)(mrandUInt(&rand) % ACCOUNTS);
from = (int)(mrandUInt(&rand) % BRANCHES);
to = (int)(mrandUInt(&rand) % BRANCHES);
val = (int)(mrandRange(1000, 100000, &rand));
val = withdraw(from, account, val);
if (val > 0)
deposit(to, account, val);
}
}
//******************************************************************************
// main program
int main(int argc, char *argv[]) {
gtimer_t timer;
mrand_t ranvar;
long assets;
// thread id's
pthread_t th[MAX_THREADS];
// get number of threads or default
if (argc > 1)
nThreads = atoi(argv[1]);
else
nThreads = NUM_THREADS;
nThreads = (nThreads > MAX_THREADS) ? MAX_THREADS : nThreads;
mrandInit((MAX_THREADS + 1)*333, &ranvar);
printf("\nRunning %d threads\n", nThreads);
makeBank(BRANCHES, ACCOUNTS);
for (int i = 0; i < ACCOUNTS; i++)
deposit(0, i, mrandRange(10, 1000*1000, &ranvar));
checkAssets();
startGTimer(timer);
// create threads and pass thread number
for (long i = 0; i < nThreads; i++)
pthread_create(&th[i], NULL, pusher, (void *)i);
// wait for threads to terminate
for (int i = 0; i < nThreads; i++)
pthread_join(th[i], NULL);
stopGTimer(timer);
checkAssets();
printGTime(timer);
}
//******************************************************************************
+32
View File
@@ -0,0 +1,32 @@
# ---------------------------------------------------------------------------
# Makefile
# Course: BSy
# Date: M. Thaler, 1/2016
# File: makefile
# Version: v.fs20
# ---------------------------------------------------------------------------
#macros
CC = gcc
CFLGS = -std=gnu99
LIBS = -pthread
OFILES = main.o banking.o
HFILES = banking.h
main: $(OFILES) $(HFILES)
$(CC) $(CFLGS) $(LIBS) $(OFILES) -o $@.e
.c.o:
$(CC) $(CFLGS) -c $<
.cc.o:
$(CC) $(CFLGS) -c $<
clean:
rm -f *.o *.e
@echo "directory cleaned"
all:
@rm -f *.o
make --no-print-directory main
#-----------------------------------------------------------------------------
+74
View File
@@ -0,0 +1,74 @@
#ifndef MY_RANDOMGENERATOR_DEFINITIONS
#define MY_RANDOMGENERATOR_DEFINITIONS
#include <sys/time.h>
#include <assert.h>
//******************************************************************************
// Course: BSy
// File: mrandom.h
// Author: M. Thaler, ZHAW
// Purpose: thread safe random functions (reentrant)
// Version: v.fs20
//******************************************************************************
// date type: mrand_t
//
// functions:
// - void mrandInit(mrand_t *mrt) -> initialize with fixed seed
// - unsigned int mrandUInt(mrand_t *mrt) -> unsigned random number
// - unsigned int mrandRange(int low, int high, mrand_t *mrt)
// -> random number within range
//
/******************************************************************************/
// constanst for ecuyer generator: length approx 8 x 10^12
#define M1 2147483563
#define M2 2147483399
#define A1 40014
#define A2 40692
#define Q1 53668
#define Q2 52774
#define R1 12211
#define R2 3791
#define MRAND_MAX M1-1
/******************************************************************************/
typedef struct mrand_t { unsigned int s1; \
unsigned int s2; } mrand_t;
void mrandInit(unsigned int seed, mrand_t *mrt) {
mrt->s1 = 33777 + seed * 777;
mrt->s2 = 9777572 + seed * 33775;
}
unsigned int mrandUInt(mrand_t *mrt) {
unsigned int rv;
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
if (mrt->s1 <= 0) mrt->s1 += M1;
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
if (mrt->s2 <= 0) mrt->s2 += M2;
rv = (mrt->s1 + mrt->s2) % M1;
return rv;
}
double mrandDouble(mrand_t *mrt) {
unsigned int rv;
double dv;
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
if (mrt->s1 <= 0) mrt->s1 += M1;
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
if (mrt->s2 <= 0) mrt->s2 += M2;
rv = (mrt->s1 + mrt->s2) % M1;
dv = (double)rv / ((double)(M1-1));
return dv;
}
unsigned int mrandRange(unsigned int low, unsigned int high, mrand_t *mrt) {
assert(low <= high);
double drv = mrandDouble(mrt);
unsigned int av = (unsigned int)(drv * (double)(high-low) + 0.5);
return low + av;
}
/******************************************************************************/
#endif
+42
View File
@@ -0,0 +1,42 @@
#ifndef TIMER_MACRO_DEFINITIONS
#define TIMER_MACRO_DEFINITIONS
/******************************************************************************/
// Course: BSy
// File: mtimer.h
// Purpose: timer functions gettimeofday()
// Author: M. Thaler, ZHAW, 1/2016
// Version: v.fs20
/******************************************************************************/
// gettimeofday()
// function: elapsed time: between start and stop
// data type: gtimer_t
// functions: startGTimer(gtimer_t tdata) -> start timer
// stopGTimer(gtimer_t tdata) -> stop timer
// double getWallGTime(gtimer_t tdata) -> get time in s
// printGTime(X) -> print time in s
//
// -> see also "man gettimeofday"
/******************************************************************************/
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
/******************************************************************************/
typedef struct gtimer_t { struct timeval sT; \
struct timeval eT; } gtimer_t;
#define startGTimer(X) gettimeofday(&X.sT, NULL)
#define stopGTimer(X) gettimeofday(&X.eT, NULL)
#define getGTime(X) ((double)(X.eT.tv_sec) - (double)(X.sT.tv_sec)) +\
((double)X.eT.tv_usec - (double)X.sT.tv_usec)/1e6
#define printGTime(X) printf("Run time %3.2lfs\n", getGTime(X))
/******************************************************************************/
#endif
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
./main.e 1
./main.e 2
./main.e 4
+19
View File
@@ -0,0 +1,19 @@
//******************************************************************************
// Course: BSy
// File: banking.h
// Author: M. Thaler, ZHAW
// Purpose: locking mechanisms
// Version: v.fs20
//******************************************************************************
// banking functions
void makeBank(int num_branches, int num_accounts);
void deleteBank(void);
long int withdraw(int branchNr, int accountNr, long int value) ;
void deposit(int branchNr, int accountNr, long int value);
void transfer(int fromB, int toB, int accountNr, long int value);
void checkAssets(void);
//******************************************************************************
+92
View File
@@ -0,0 +1,92 @@
//******************************************************************************
// Course: BSy
// File: main.c
// Author: M. Thaler, ZHAW
// Purpose: locking mechanisms
// Version: v.fs20
//******************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "banking.h"
#include "mtimer.h"
#include "mrandom.h"
//******************************************************************************
// constant values
#define MAX_THREADS 16
#define NUM_THREADS 4
#define TRANSFERS (16*1024*1024)
#define ACCOUNTS (2048)
#define BRANCHES (128)
//******************************************************************************
// globals
int nThreads;
//******************************************************************************
// pusher
void *pusher(void *arg) {
int idx = (int)(long)(arg);
mrand_t rand;
unsigned int seed = 17*idx;
mrandInit(seed, &rand);
int account, from, to, val;
int count = TRANSFERS / nThreads;
for (int i = 0; i < count; i++) {
account = (int)(mrandUInt(&rand) % ACCOUNTS);
from = (int)(mrandUInt(&rand) % BRANCHES);
to = (int)(mrandUInt(&rand) % BRANCHES);
val = (int)(mrandRange(1000, 100000, &rand));
val = withdraw(from, account, val);
deposit(to, account, val);
}
}
//******************************************************************************
// main program
int main(int argc, char *argv[]) {
gtimer_t timer;
mrand_t ranvar;
long assets;
// thread id's
pthread_t th[MAX_THREADS];
// get number of threads or default
if (argc > 1)
nThreads = atoi(argv[1]);
else
nThreads = NUM_THREADS;
nThreads = (nThreads > MAX_THREADS) ? MAX_THREADS : nThreads;
mrandInit((MAX_THREADS + 1)*333, &ranvar);
printf("\nRunning %d threads\n", nThreads);
makeBank(BRANCHES, ACCOUNTS);
for (int i = 0; i < ACCOUNTS; i++)
deposit(0, i, mrandRange(10, 1000*1000, &ranvar));
checkAssets();
startGTimer(timer);
// create threads and pass thread number
for (long i = 0; i < nThreads; i++)
pthread_create(&th[i], NULL, pusher, (void *)i);
// wait for threads to terminate
for (int i = 0; i < nThreads; i++)
pthread_join(th[i], NULL);
stopGTimer(timer);
checkAssets();
printGTime(timer);
}
//******************************************************************************
+32
View File
@@ -0,0 +1,32 @@
# ---------------------------------------------------------------------------
# Makefile
# Course: BSy
# Date: M. Thaler, 1/2016
# File: makefile
# Version: v.fs20
# ---------------------------------------------------------------------------
#macros
CC = gcc
CFLGS = -std=gnu99
LIBS = -pthread
OFILES = main.o banking.o
HFILES = banking.h
main: $(OFILES) $(HFILES)
$(CC) $(CFLGS) $(LIBS) $(OFILES) -o $@.e
.c.o:
$(CC) $(CFLGS) -c $<
.cc.o:
$(CC) $(CFLGS) -c $<
clean:
rm -f *.o *.e
@echo "directory cleaned"
all:
@rm -f *.o
make --no-print-directory main
#-----------------------------------------------------------------------------
+74
View File
@@ -0,0 +1,74 @@
#ifndef MY_RANDOMGENERATOR_DEFINITIONS
#define MY_RANDOMGENERATOR_DEFINITIONS
#include <sys/time.h>
#include <assert.h>
//******************************************************************************
// Course: BSy
// File: mrandom.h
// Author: M. Thaler, ZHAW
// Purpose: thread safe random functions (reentrant)
// Version: v.fs20
//******************************************************************************
// date type: mrand_t
//
// functions:
// - void mrandInit(mrand_t *mrt) -> initialize with fixed seed
// - unsigned int mrandUInt(mrand_t *mrt) -> unsigned random number
// - unsigned int mrandRange(int low, int high, mrand_t *mrt)
// -> random number within range
//
/******************************************************************************/
// constanst for ecuyer generator: length approx 8 x 10^12
#define M1 2147483563
#define M2 2147483399
#define A1 40014
#define A2 40692
#define Q1 53668
#define Q2 52774
#define R1 12211
#define R2 3791
#define MRAND_MAX M1-1
/******************************************************************************/
typedef struct mrand_t { unsigned int s1; \
unsigned int s2; } mrand_t;
void mrandInit(unsigned int seed, mrand_t *mrt) {
mrt->s1 = 33777 + seed * 777;
mrt->s2 = 9777572 + seed * 33775;
}
unsigned int mrandUInt(mrand_t *mrt) {
unsigned int rv;
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
if (mrt->s1 <= 0) mrt->s1 += M1;
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
if (mrt->s2 <= 0) mrt->s2 += M2;
rv = (mrt->s1 + mrt->s2) % M1;
return rv;
}
double mrandDouble(mrand_t *mrt) {
unsigned int rv;
double dv;
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
if (mrt->s1 <= 0) mrt->s1 += M1;
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
if (mrt->s2 <= 0) mrt->s2 += M2;
rv = (mrt->s1 + mrt->s2) % M1;
dv = (double)rv / ((double)(M1-1));
return dv;
}
unsigned int mrandRange(unsigned int low, unsigned int high, mrand_t *mrt) {
assert(low <= high);
double drv = mrandDouble(mrt);
unsigned int av = (unsigned int)(drv * (double)(high-low) + 0.5);
return low + av;
}
/******************************************************************************/
#endif
+42
View File
@@ -0,0 +1,42 @@
#ifndef TIMER_MACRO_DEFINITIONS
#define TIMER_MACRO_DEFINITIONS
/******************************************************************************/
// Course: BSy
// File: mtimer.h
// Purpose: timer functions gettimeofday()
// Author: M. Thaler, ZHAW, 1/2016
// Version: v.fs20
/******************************************************************************/
// gettimeofday()
// function: elapsed time: between start and stop
// data type: gtimer_t
// functions: startGTimer(gtimer_t tdata) -> start timer
// stopGTimer(gtimer_t tdata) -> stop timer
// double getWallGTime(gtimer_t tdata) -> get time in s
// printGTime(X) -> print time in s
//
// -> see also "man gettimeofday"
/******************************************************************************/
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
/******************************************************************************/
typedef struct gtimer_t { struct timeval sT; \
struct timeval eT; } gtimer_t;
#define startGTimer(X) gettimeofday(&X.sT, NULL)
#define stopGTimer(X) gettimeofday(&X.eT, NULL)
#define getGTime(X) ((double)(X.eT.tv_sec) - (double)(X.sT.tv_sec)) +\
((double)X.eT.tv_usec - (double)X.sT.tv_usec)/1e6
#define printGTime(X) printf("Run time %3.2lfs\n", getGTime(X))
/******************************************************************************/
#endif
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
./main.e 1
./main.e 2
./main.e 4
+127
View File
@@ -0,0 +1,127 @@
//******************************************************************************
// Course: BSy
// File: banking.c
// Author: M. Thaler, ZHAW
// Purpose: locking mechanisms
// Version: v.fs20
//******************************************************************************
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include "banking.h"
//******************************************************************************
typedef struct account_struct_ {
long int balance;
pthread_mutex_t acntLock;
} Account;
typedef struct branch_struct {
Account *accounts;
pthread_mutex_t branchLock;
} Branch;
//******************************************************************************
static Branch *bank;
static int nBranches, nAccounts;
//******************************************************************************
// banking functions
void makeBank(int num_branches, int num_accounts) {
nBranches = num_branches;
nAccounts = num_accounts;
bank = (Branch *)malloc(nBranches * sizeof(Branch));
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
//pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
for (int i = 0; i < nBranches; i++) {
bank[i].accounts = (Account *)malloc(nAccounts * sizeof(Account));
for (int j = 0; j < nAccounts; j++) {
pthread_mutex_init(&bank[i].accounts[j].acntLock, NULL);
bank[i].accounts[j].balance = 0;
}
}
}
void deletebank(void) {
for (int i = 0; i < nBranches; i++)
free(bank[i].accounts);
free(bank);
nBranches = nAccounts = 0;
}
long int withdraw(int branchNr, int accountNr, long int value) {
int rv, tmp;
rv = 0;
tmp = bank[branchNr].accounts[accountNr].balance - value;
if (tmp >= 0) {
bank[branchNr].accounts[accountNr].balance = tmp;
rv = value;
};
return rv;
}
void deposit(int branchNr, int accountNr, long int value) {
bank[branchNr].accounts[accountNr].balance += value;
}
void transfer(int fromB, int toB, int accountNr, long int value) {
int money = withdraw(fromB, accountNr, value);
deposit(toB, accountNr, money);
}
void checkAssets(void) {
static long assets = 0;
long int sum = 0;
for (int i = 0; i < nBranches; i++) {
for (int j = 0; j < nAccounts; j++) {
sum += (long int)bank[i].accounts[j].balance;
}
}
if (assets == 0) {
assets = sum;
printf("Balance of accounts is: %ld\n", sum);
}
else {
if (sum != assets) {
printf("Balance of accounts is: %ld ... not correct\n", sum);
}
else
printf("Balance of accounts is: %ld ... correct\n", assets);
}
}
int checkIBC(void) {
static long ibcError = 0;
long sum = 0;
for (int i = 0; i < nBranches; i++) {
pthread_mutex_lock(&bank[i].branchLock);
for (int j = 0; j < nAccounts; j++) {
pthread_mutex_lock(&bank[i].accounts[j].acntLock);
}
}
for (int i = 0; i < nBranches; i++) {
for (int j = 0; j < nAccounts; j++) {
sum += (long)bank[i].accounts[j].balance;
}
}
for (int i = nBranches - 1; i >= 0; i--) {
pthread_mutex_unlock(&bank[i].branchLock);
for (int j = 0; j < nAccounts; j++) {
pthread_mutex_unlock(&bank[i].accounts[j].acntLock);
}
}
if (ibcError == 0) ibcError = sum;
return (ibcError != sum);
}
//******************************************************************************
+20
View File
@@ -0,0 +1,20 @@
//******************************************************************************
// Course: BSy
// File: banking.h
// Author: M. Thaler, ZHAW
// Purpose: locking mechanisms
// Version: v.fs20
//******************************************************************************
// banking functions
void makeBank(int num_branches, int num_accounts);
void deleteBank(void);
long withdraw(int branch, int account, long int value) ;
void deposit(int branch, int account, long int value);
void transfer(int fromB, int toB, int account, long int value);
void checkAssets(void);
int checkIBC(void);
//******************************************************************************
+107
View File
@@ -0,0 +1,107 @@
//******************************************************************************
// Course: BSy
// File: main.c
// Author: M. Thaler, ZHAW
// Purpose: locking mechanisms
// Version: v.fs20
//******************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "banking.h"
#include "mtimer.h"
#include "mrandom.h"
//******************************************************************************
// constant values
#define MAX_THREADS 16
#define NUM_THREADS 5
#define TRANSFERS (16*1024*1024L)
#define ACCOUNTS (2048)
#define BRANCHES (128)
//******************************************************************************
// globals
int nThreads;
int ibc = 0;
//******************************************************************************
// customers
void *pusher(void *arg) {
int idx = (int)(long)(arg);
mrand_t rand;
unsigned int seed = 17*idx;
mrandInit(seed, &rand);
int account, from, to, val;
int count = TRANSFERS / nThreads;
for (int i = 0; i < count; i++) {
account = (int)(mrandUInt(&rand) % ACCOUNTS);
from = (int)(mrandUInt(&rand) % BRANCHES);
to = (int)(mrandUInt(&rand) % BRANCHES);
val = (int)(mrandRange(1000, 100000, &rand));
transfer(from, to, account, val);
}
}
void *checker(void *arg) {
for (int i = 0; i < 1000; i = i) {
ibc += checkIBC();
usleep(100*1000);
}
}
//******************************************************************************
// main program
int main(int argc, char *argv[]) {
gtimer_t timer;
mrand_t ranvar;
long assets;
// thread id's
pthread_t th[MAX_THREADS];
// get number of threads or default
if (argc > 1)
nThreads = atoi(argv[1]);
else
nThreads = NUM_THREADS;
nThreads = (nThreads > MAX_THREADS) ? MAX_THREADS : nThreads;
mrandInit((MAX_THREADS + 1)*333, &ranvar);
printf("\nRunning %d threads\n", nThreads);
makeBank(BRANCHES, ACCOUNTS);
for (int i = 0; i < ACCOUNTS; i++)
deposit(0, i, mrandRange(10, 1000*1000, &ranvar));
checkAssets();
startGTimer(timer);
// create threads and pass thread number
pthread_create(&th[0], NULL, checker, (void *)0);
sleep(1);
for (long i = 1; i < nThreads; i++)
pthread_create(&th[i], NULL, pusher, (void *)i);
// wait for threads to terminate
for (int i = 1; i < nThreads; i++)
pthread_join(th[i], NULL);
stopGTimer(timer);
checkAssets();
printGTime(timer);
if (ibc)
printf("\n\033[41mYou do not comply with the IBC rules \033[0m\n\n");
else
printf("\n\033[42mYou do comply with the IBC rules \033[0m\n\n");
}
//******************************************************************************
+32
View File
@@ -0,0 +1,32 @@
# ---------------------------------------------------------------------------
# Makefile
# Course: BSy
# Date: M. Thaler, 1/2016
# File: makefile
# Version: v.fs20
# ---------------------------------------------------------------------------
#macros
CC = gcc
CFLGS = -std=gnu99
LIBS = -pthread
OFILES = main.o banking.o
HFILES = banking.h
main: $(OFILES) $(HFILES)
$(CC) $(CFLGS) $(LIBS) $(OFILES) -o $@.e
.c.o:
$(CC) $(CFLGS) -c $<
.cc.o:
$(CC) $(CFLGS) -c $<
clean:
rm -f *.o *.e
@echo "directory cleaned"
all:
@rm -f *.o
make --no-print-directory main
#-----------------------------------------------------------------------------
+74
View File
@@ -0,0 +1,74 @@
#ifndef MY_RANDOMGENERATOR_DEFINITIONS
#define MY_RANDOMGENERATOR_DEFINITIONS
#include <sys/time.h>
#include <assert.h>
//******************************************************************************
// Course: BSy
// File: mrandom.h
// Author: M. Thaler, ZHAW
// Purpose: thread safe random functions (reentrant)
// Version: v.fs20
//******************************************************************************
// date type: mrand_t
//
// functions:
// - void mrandInit(mrand_t *mrt) -> initialize with fixed seed
// - unsigned int mrandUInt(mrand_t *mrt) -> unsigned random number
// - unsigned int mrandRange(int low, int high, mrand_t *mrt)
// -> random number within range
//
/******************************************************************************/
// constanst for ecuyer generator: length approx 8 x 10^12
#define M1 2147483563
#define M2 2147483399
#define A1 40014
#define A2 40692
#define Q1 53668
#define Q2 52774
#define R1 12211
#define R2 3791
#define MRAND_MAX M1-1
/******************************************************************************/
typedef struct mrand_t { unsigned int s1; \
unsigned int s2; } mrand_t;
void mrandInit(unsigned int seed, mrand_t *mrt) {
mrt->s1 = 33777 + seed * 777;
mrt->s2 = 9777572 + seed * 33775;
}
unsigned int mrandUInt(mrand_t *mrt) {
unsigned int rv;
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
if (mrt->s1 <= 0) mrt->s1 += M1;
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
if (mrt->s2 <= 0) mrt->s2 += M2;
rv = (mrt->s1 + mrt->s2) % M1;
return rv;
}
double mrandDouble(mrand_t *mrt) {
unsigned int rv;
double dv;
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
if (mrt->s1 <= 0) mrt->s1 += M1;
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
if (mrt->s2 <= 0) mrt->s2 += M2;
rv = (mrt->s1 + mrt->s2) % M1;
dv = (double)rv / ((double)(M1-1));
return dv;
}
unsigned int mrandRange(unsigned int low, unsigned int high, mrand_t *mrt) {
assert(low <= high);
double drv = mrandDouble(mrt);
unsigned int av = (unsigned int)(drv * (double)(high-low) + 0.5);
return low + av;
}
/******************************************************************************/
#endif
+42
View File
@@ -0,0 +1,42 @@
#ifndef TIMER_MACRO_DEFINITIONS
#define TIMER_MACRO_DEFINITIONS
/******************************************************************************/
// Course: BSy
// File: mtimer.h
// Purpose: timer functions gettimeofday()
// Author: M. Thaler, ZHAW, 1/2016
// Version: v.fs20
/******************************************************************************/
// gettimeofday()
// function: elapsed time: between start and stop
// data type: gtimer_t
// functions: startGTimer(gtimer_t tdata) -> start timer
// stopGTimer(gtimer_t tdata) -> stop timer
// double getWallGTime(gtimer_t tdata) -> get time in s
// printGTime(X) -> print time in s
//
// -> see also "man gettimeofday"
/******************************************************************************/
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
/******************************************************************************/
typedef struct gtimer_t { struct timeval sT; \
struct timeval eT; } gtimer_t;
#define startGTimer(X) gettimeofday(&X.sT, NULL)
#define stopGTimer(X) gettimeofday(&X.eT, NULL)
#define getGTime(X) ((double)(X.eT.tv_sec) - (double)(X.sT.tv_sec)) +\
((double)X.eT.tv_usec - (double)X.sT.tv_usec)/1e6
#define printGTime(X) printf("Run time %3.2lfs\n", getGTime(X))
/******************************************************************************/
#endif
+4
View File
@@ -0,0 +1,4 @@
#!/bin/bash
./main.e 1
./main.e 2
./main.e 4
@@ -0,0 +1,46 @@
/*******************************************************************************
* File: coffeTeller.c
* Purpose: simple sequence with semaphores
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012, 7/2013
* Version: v.fs20
*******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <semaphore.h>
#include "commonDefs.h"
//******************************************************************************
int main(void) {
int i;
sem_t *coin, *coffee, *ready;
// set up a semaphore
coin = sem_open(COIN_SEMAPHOR, 0);
coffee = sem_open(COFFEE_SEMAPHOR, 0);
ready = sem_open(READY_SEMAPHOR, 0);
// start teller machine
printf("\nCoffee teller machine starting\n\n");
i = 0;
while (i < ITERS) {
printf("teller (%d): waiting for coin\n", i);
printf(" (%d): got coin\n", i);
printf(" (%d): dispense coffee\n", i);
i++;
}
}
//******************************************************************************
@@ -0,0 +1,30 @@
#ifndef MY_DEFINITIONS_HEADER
#define MY_DEFINITIONS_HEADER
/*******************************************************************************
* File: commonDefs.h
* Purpose: common definitions
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012, 7/2013, 4/2014
* Version: v.fs20
*******************************************************************************/
#define MYTURN_SEMAPHOR "/my_semaphor_1_name_simple_seq"
#define COIN_SEMAPHOR "/my_semaphor_2_name_simple_seq"
#define COFFEE_SEMAPHOR "/my_semaphor_3_name_simple_seq"
#define READY_SEMAPHOR "/my_semaphor_4_name_simple_seq"
#define ITERS (100*1000*1000)
#define CUSTOMERS 4
//******************************************************************************
#define checkSem(X) {if (X == SEM_FAILED) {perror("sem_open"); exit(-1);}}
#define drinkingCoffee(X) {usleep((((1+X)*rand())+100000)&0xFFFFF);}
//******************************************************************************
#endif
@@ -0,0 +1,50 @@
/*******************************************************************************
* File: customer.c
* Purpose: simple sequence with semaphores
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012, 7/2013
* Version: v.fs20
*******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <semaphore.h>
#include "commonDefs.h"
//******************************************************************************
int main(int argc, char *argv[]) {
int i, myID;
sem_t *myTurn, *coin, *coffee, *ready;
if (argc > 1)
myID = atoi(argv[1]);
else
myID = 0;
// set up a semaphore
myTurn = sem_open(MYTURN_SEMAPHOR, 0);
coin = sem_open(COIN_SEMAPHOR, 0);
coffee = sem_open(COFFEE_SEMAPHOR, 0);
ready = sem_open(READY_SEMAPHOR, 0);
// start customer
printf("Customer starting (%d)\n", myID);
// now check the sum
for (i = 0; i < ITERS; i++) {
printf("\t\t\t\tcustomer(%d) put coin %d\n", myID, i);
printf("\t\t\t\tcustomer(%d) waiting for coffee %d\n", myID, i);
printf("\t\t\t\tcustomer(%d) got coffee %d\n", myID, i);
drinkingCoffee(myID);
}
}
//******************************************************************************
+40
View File
@@ -0,0 +1,40 @@
# Author M. Thaler InIT/ZHAW
# Version v.fs20
CMP= gcc -std=gnu99
CMPFLAGS= -Wall -g
LIB= -pthread
EXENAME0= startApp.e
EXENAME1= coffeeTeller.e
EXENAME2= customer.e
doit:
@make --no-print-directory clean
@make --no-print-directory startApp
@make --no-print-directory coffeeTeller
@make --no-print-directory customer
startApp: startApp.o
$(CMP) $(CMPFLAGS) startApp.o $(LIB) -o $(EXENAME0)
coffeeTeller: coffeeTeller.o
$(CMP) $(CMPFLAGS) coffeeTeller.o $(LIB) -o $(EXENAME1)
customer: customer.o
$(CMP) $(CMPFLAGS) customer.o $(LIB) -o $(EXENAME2)
.c.o:
$(CMP) -c $(CMPFLAGS) $<
.cc.o:
$(CMP) -c $(CMPFLAGS) $<
all:
@make clean
make doit
clean:
@rm -f *.e *.o
purge:
@make clean
@@ -0,0 +1,72 @@
/*******************************************************************************
* File: startApp.c
* Purpose: ice cream teller, basic sequence
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012, 7/2013
* Version: v.fs20
*******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <semaphore.h>
#include "commonDefs.h"
//******************************************************************************
int main(void) {
int j;
char string[8];
sem_t *myTurn, *coin, *coffee, *ready;
pid_t tellerPID;
sem_unlink(MYTURN_SEMAPHOR); // delete seamphor if it still exists
sem_unlink(COIN_SEMAPHOR); // delete seamphor if it still exists
sem_unlink(COFFEE_SEMAPHOR); // delete seamphor if it still exists
sem_unlink(READY_SEMAPHOR); // delete seamphor if it still exists
// set up a semaphore (? -> initial value of semaphor)
// checkSem() -> macro defined in commonDefs.h
/*
myTurn = sem_open(MYTURN_SEMAPHOR, O_CREAT, 0700, ?); checkSem(myTurn);
coin = sem_open(COIN_SEMAPHOR, O_CREAT, 0700, ?); checkSem(coin);
coffee = sem_open(COFFEE_SEMAPHOR, O_CREAT, 0700, ?); checkSem(coffee);
ready = sem_open(READY_SEMAPHOR, O_CREAT, 0700, ?); checkSem(ready);
*/
// now that the resources are set up, the supervisor can be started
for (j = 1; j <= CUSTOMERS; j++) {
if (fork() == 0) {
sprintf(string, "%d", j);
execl("./customer.e", "customer.e", string, NULL);
printf("*** could not start customer.e ***\n");
}
}
if ((tellerPID = fork()) == 0) {
execl("./coffeeTeller.e", "coffeeTeller.e", "0", NULL);
printf("*** could not start coffeTeller ***\n");
}
waitpid(tellerPID, NULL, 0);
system("killall coffeeTeller.e");
system("killall customer.e"); // kill all customers
// clean up resources
sem_unlink(MYTURN_SEMAPHOR);
sem_unlink(COIN_SEMAPHOR);
sem_unlink(COFFEE_SEMAPHOR);
sem_unlink(READY_SEMAPHOR);
printf("\n");
}
//******************************************************************************
+56
View File
@@ -0,0 +1,56 @@
#!/bin/bash
#******************************************************************************
# Purpose: turn off all CPU's but one (CPU 0), turn on all CPU's
# Linux only
# Author: M. Thaler, BSy 4/2014
# Usage: multiCPUs off: turn off all CPUs but one
# multiCPUs on: turn all CPUs on
#
# Version: v.fs20
#******************************************************************************
theDir="/sys/devices/system/cpu"
# check if sys exists
if test ! -d $theDir
then
echo "*** cannot set to single CPU ***"
exit 1
fi
# figure out what to do: multi CPUs off (single CPU) or all CPU's on
let status=1
if test "$1" = "on"
then
let status=1
else
if test "$1" = "off"
then
let status=0
else
echo "*** what do you want: ... on or off? ***"
exit 1
fi
fi
# turn CPU's on or off
cd $theDir
CPUs=`ls -d cpu* | grep 'cpu[0-9][0-9]*'`
for CPU in $CPUs
do
if test ! "$CPU" = "cpu0"
then
echo "$CPU on = $status"
currVal=`cat ./$CPU/online`
# only change if different ... avoid error message
if test ! "$currVal" = "$status"
then
echo "$status" > "./$CPU/online"
fi
fi
done
#******************************************************************************
+7
View File
@@ -0,0 +1,7 @@
For Mac users
"pthread_mutex_lock(&lock)" is slow on MACs compared to Linux:
use instead: "while (pthread_mutex_trylock(&lock) > 0) {} ;"
which implements a spin lock
+46
View File
@@ -0,0 +1,46 @@
/*******************************************************************************
* File: coffeTeller.c
* Purpose: coffe teller with pthreads
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012
* Version: v.fs20
*******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
#include "commonDefs.h"
//******************************************************************************
void *coffeeTeller(void* data) {
int i;
cData *cD = (cData *) data;
// now start selling coffee
printf("\nCoffee teller machine starting\n\n");
i = 0;
while (i < ITERATIONS) {
if (cD->coinCount != cD->selCount1 + cD->selCount2) {
printf("error c = %5d s1 =%6d s2 =%6d diff: %4d\ti = %d\n",
cD->coinCount, cD->selCount1, cD->selCount2,
cD->coinCount - cD->selCount1 - cD->selCount2,
i);
cD->coinCount = 0;
cD->selCount1 = cD->selCount2 = 0;
}
if (i%1000000 == 0) printf("working %d\n", i);
i++;
}
pthread_exit(0);
}
//******************************************************************************
+17
View File
@@ -0,0 +1,17 @@
#ifndef MY_DEFINITIONS_TELLER_H
#define MY_DEFINITIONS_TELLER_H
/*******************************************************************************
* File: coffeTeller.h
* Purpose: coffe teller with pthreads
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012
* Version: v.fs20
*******************************************************************************/
void *coffeeTeller(void* data);
//******************************************************************************
#endif
+32
View File
@@ -0,0 +1,32 @@
#ifndef MY_DEFINITIONS_HEADER
#define MY_DEFINITIONS_HEADER
/*******************************************************************************
* File: commonDefs.h
* Purpose: header file for common definitions
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012
* Version: v.fs20
*******************************************************************************/
#define ITERATIONS (100*1000*1000)
//******************************************************************************
#define CUSTOMERS 4 // number of customers to be started
//******************************************************************************
// common data
typedef struct {
int coinCount; // number of paid coffees
int selCount1; // number of chosen coffees of type 1
int selCount2; // number of chosen coffees of type 2
pthread_mutex_t lock; // common lock
} cData;
//******************************************************************************
#endif
+44
View File
@@ -0,0 +1,44 @@
/*******************************************************************************
* File: customer.c
* Purpose: customer thread
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012
* Version: v.fs20
*******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include "commonDefs.h"
#include "mrand.h"
//*****************************************************************************
void *customer(void* data) {
float ranNum;
int i;
rand_t randnum;
cData *cD = (cData *) data;
rand_seed(&randnum, 0);
// put coin and select coffee
for (i = 0; i < ITERATIONS; i++) {
ranNum = rand_float(&randnum);
cD->coinCount += 1;
if (ranNum < 0.5)
cD->selCount1 += 1;
else
cD->selCount2 += 1;
}
pthread_exit(0);
}
//*****************************************************************************
+16
View File
@@ -0,0 +1,16 @@
#ifndef MY_DEFINITIONS_CUSTOMER_H
#define MY_DEFINITIONS_CUSTOMER_H
/*******************************************************************************
* File: customer.h
* Purpose: customer thread
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012
* Version: v.fs20
*******************************************************************************/
void *customer(void* data);
//******************************************************************************
#endif
+33
View File
@@ -0,0 +1,33 @@
# Author M. Thaler
# Version v.fs20
CMP= gcc -std=gnu99
CMPFLAGS= -Wall -g
LIB= -pthread
EXENAME1= startApp.e
INCLS= commonDefs.h
FILES= startApp.o coffeeTeller.o customer.o
doit:
@make --no-print-directory clean
@make --no-print-directory coffeeTeller
coffeeTeller: $(FILES)
$(CMP) $(CMPFLAGS) $(FILES) $(LIB) -o $(EXENAME1)
.c.o: $(INCLS)
$(CMP) -c $(CMPFLAGS) $<
.cc.o: $(INCLS)
$(CMP) -c $(CMPFLAGS) $<
all:
@make clean
make doit
clean:
@rm -f *.e *.o
purge:
@make clean
+102
View File
@@ -0,0 +1,102 @@
#ifndef MY_THREADSAVE_RANDOM_GENERATOR
#define MY_THREADSAVE_RANDOM_GENERATOR
/******************************************************************************
* File: mrand.h
* Purpose: simple portable thread save random generator
* ccording to Schrage
* Author: M. Thaler, 5/2012, BSy
* Version: v.fs20
******************************************************************************/
#include <sys/time.h>
//******************************************************************************
#define MMM_MR 2147483563
#define AAA_MR 40014
#define QQQ_MR 53668
#define RRR_MR 12211
#define MRAND_MAX (MMM_MR-1)
//******************************************************************************
typedef int rand_t;
// seed ------------------------------------------------------------------------
void rand_seed(rand_t *srand, int seed) {
struct timeval prandom_seed;
gettimeofday(&prandom_seed, NULL);
if (seed > 0)
*srand = seed;
else
*srand = (prandom_seed.tv_usec);
}
// integer random value -------------------------------------------------------
// range 0 .. MRAND_MAX (inclusive)
int rand_int(rand_t *srand) {
int nx;
nx = AAA_MR * (*srand % QQQ_MR) - RRR_MR * (*srand / QQQ_MR);
*srand = (nx > 0) ? nx : nx + MMM_MR;
return (*srand);
}
// float random value ---------------------------------------------------------
// range 0.0 .. 1.0 (inclusive)
float rand_float(rand_t *srand) {
float fx;
*srand = rand_int(srand);
fx = (float)(*srand) / ((float)MRAND_MAX);
return (fx);
}
// double random value --------------------------------------------------------
// range 0.0 .. 1.0 (inclusive)
double rand_double(rand_t *srand) {
double fx;
*srand = rand_int(srand);
fx = (double)(*srand) / ((double)MRAND_MAX);
return (fx);
}
// unsigned int random range --------------------------------------------------
// range low .. high
unsigned int rand_range(unsigned int low, unsigned int high, rand_t *srand) {
unsigned int rv;
double prop;
prop = ((double)(high - low)) * rand_double(srand);
rv = low + ((unsigned int) prop);
return(rv);
}
// unsigned int probability ---------------------------------------------------
// returns 0 or 1
unsigned int rand_prob(double prob, rand_t *srand) {
if (rand_double(srand) >= 1.0-prob)
return 1;
else
return 0;
}
// unsigned int toss coin -----------------------------------------------------
// returns 0 or 1
unsigned int toss_coin(rand_t *srand) {
if (rand_float(srand) >= 0.5)
return 1;
else
return 0;
}
//******************************************************************************
#endif
+59
View File
@@ -0,0 +1,59 @@
/*******************************************************************************
* File: startApp.c
* Purpose: mutex with locks
* Course: bsy
* Author: M. Thaler, 2011
* Revision: 5/2012
* Version: v.fs20
*******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>
#include <pthread.h>
#include "commonDefs.h"
#include "coffeeTeller.h"
#include "customer.h"
//******************************************************************************
// common data
cData cD;
//******************************************************************************
int main(void) {
unsigned int j;
int pthr;
pthread_t tellerThread, customerThreads[CUSTOMERS];
cD.coinCount = 0;
cD.selCount1 = 0;
cD.selCount2 = 0;
pthread_mutex_init(&(cD.lock), NULL);
// start teller and customers now that everything is set up
pthr = pthread_create(&tellerThread, NULL, coffeeTeller, &cD);
assert(pthr == 0);
for (j = 0; j < CUSTOMERS; j++) {
pthr = pthread_create(&(customerThreads[j]), NULL, customer, &cD);
assert(pthr == 0);
}
// wait for all threads to terminate
pthread_join(tellerThread, NULL);
for (j = 0; j < CUSTOMERS; j++) {
pthr = pthread_join(customerThreads[j], NULL);
assert(pthr == 0);
}
}
//******************************************************************************