Thread-Synchronisation
A03.cs
using System;
using System.Threading;
class Buffer {
char[] buf;
int head, tail, n;
int size;
public Buffer(int size) {
buf = new char[size];
this.size = size;
head = tail = n = 0;
}
public void Put(char ch) {
Console.WriteLine(Thread.CurrentThread.Name + " calls Put");
lock(this) {
Console.WriteLine(Thread.CurrentThread.Name + " access granted");
while (n == size) Monitor.Wait(this);
buf[tail] = ch; tail = (tail + 1) % size; n++;
Console.WriteLine(Thread.CurrentThread.Name + " ready: n=" + n);
Console.WriteLine();
Monitor.Pulse(this);
}
}
public char Get() {
Console.WriteLine(Thread.CurrentThread.Name + " calls Get");
lock(this) {
Console.WriteLine(Thread.CurrentThread.Name + " access granted");
while (n == 0) Monitor.Wait(this);
char ch = buf[head]; head = (head + 1) % size; n--;
Console.WriteLine(Thread.CurrentThread.Name + " ready: n=" + n);
Console.WriteLine();
Monitor.Pulse(this);
return ch;
}
}
}
class BufferTest {
static Buffer buf = new Buffer(4);
static Random rand = new Random();
static void Produce() {
for (int i = 0; i < 5; i++) {
buf.Put('x');
Thread.Sleep(rand.Next(1000));
}
}
static void Consume() {
for (int i = 0; i < 5; i++) {
char ch = buf.Get();
Thread.Sleep(rand.Next(100));
}
}
static void Main(string[] arg) {
Thread p1 = new Thread(new ThreadStart(Produce));
Thread p2 = new Thread(new ThreadStart(Produce));
Thread c1 = new Thread(new ThreadStart(Consume));
Thread c2 = new Thread(new ThreadStart(Consume));
p1.Name = "Prod1"; p2.Name = "Prod2";
c1.Name = "Cons1"; c2.Name = "Cons2";
p1.Start(); p2.Start(); c1.Start(); c2.Start();
}
}
|
Dieses Programm liefert zum Beispiel folgende Ausgabe:
Prod1 calls Put
Prod1 access granted
Prod2 calls Put
Cons1 calls Get
Cons2 calls Get
Prod1 ready: n=1
Prod2 access granted
Prod2 ready: n=2
Cons1 access granted
Cons1 ready: n=1
Cons2 access granted
Cons2 ready: n=0
Cons1 calls Get
Cons1 access granted
Prod2 calls Put
Prod2 access granted
Prod2 ready: n=1
Cons2 calls Get
Cons2 access granted
Cons2 ready: n=0
Prod1 calls Put
Prod1 access granted
Prod1 ready: n=1
Cons1 ready: n=0
Cons1 calls Get
Cons1 access granted
Cons2 calls Get
Cons2 access granted
Prod1 calls Put
Prod1 access granted
Prod1 ready: n=1
Cons1 ready: n=0
Cons1 calls Get
Cons1 access granted
Prod1 calls Put
Prod1 access granted
Prod1 ready: n=1
Cons2 ready: n=0
Cons2 calls Get
Cons2 access granted
Prod2 calls Put
Prod2 access granted
Prod2 ready: n=1
Cons1 ready: n=0
Cons1 calls Get
Cons1 access granted
Prod1 calls Put
Prod1 access granted
Prod1 ready: n=1
Cons2 ready: n=0
Cons2 calls Get
Cons2 access granted
Prod2 calls Put
Prod2 access granted
Prod2 ready: n=1
Cons1 ready: n=0
Prod2 calls Put
Prod2 access granted
Prod2 ready: n=1
Cons2 ready: n=0
Da die Consumer-Threads hier schneller sind als die Producer-Threads,
finden sie immer wieder einmal einen leeren Puffer vor und
müssen warten, bis ein Producer wieder Daten im Puffer abgelegt
hat.
|