A C#/Mono Multi-threaded, blocking queue
Meanwhile… Playtime with Mono on my PowerBook continues…
Moving from Java to Cocoa… the feature I missed the most in Objective-C was a modern, object-oriented threading toolkit. Java has excellent threading support and a mature, full-featured (especially as of 5.0) OO threading toolkit. Cocoa does not (I’d be thrilled to be proven wrong here… but after quite a bit of looking, I’d be surprised).
Since C# is largely a Java rip-off (save the flames, we all know its true)… guess what? They have an excellent OO threading toolkit too! And guess what else? It looks almost exactly like Java’s! Yeah!
iTod haaaaaaaaaaaaappy.
Here’s my first experimentation with Mono’s System.Threading package… a multi-threaded blocking queue that has a maximum size limit (5 in this example) inspired by an example in the Java Tutorial. (And no… this is not an attempt at good API design… just a little experimentation.)
//QueueTest.cs
using System;
using System.Threading;
using System.Collections;
public class QueueTest {
static int Total = 20;
static int Max = 5;
static Random rand = new Random();
static BlockingQueue q = new BlockingQueue();
static void Main() {
Producer p = new Producer(1);
Consumer c = new Consumer(1);
new Thread(new ThreadStart(c.Run)).Start();
new Thread(new ThreadStart(p.Run)).Start();
}
class BlockingQueue {
private ArrayList list = new ArrayList(Max);
public void put(int val, int id) {
lock (this) {
while (list.Count == Max) {
Monitor.Wait(this);
}
list.Add(val);
Console.WriteLine("Producer #{0} put: {1}, size : {2}",
id, val, list.Count);
Monitor.Pulse(this);
}
}
public int get(int id) {
lock (this) {
while (list.Count == 0) {
Monitor.Wait(this);
}
int result = (int)list[0];
list.RemoveAt(0);
Console.WriteLine("Consumer #{0} got: {1}, size : {2}",
id, result, list.Count);
Monitor.Pulse(this);
return result;
}
}
}
class Producer {
private int id;
public Producer(int id) {
this.id = id;
}
public void Run() {
for (int i = 0; i < Total; i++) {
q.put(i, id);
Thread.Sleep(rand.Next(50));
}
}
}
class Consumer {
private int id;
public Consumer(int id) {
this.id = id;
}
public void Run() {
for (int i = 0; i < Total; i++) {
q.get(id);
Thread.Sleep(rand.Next(500));
}
}
}
}
The following command compile and run the code on my PB:
(Todd-Ditchendorfs-Computer) 02:04 PM QueueTest) mcs QueueTest.cs
(Todd-Ditchendorfs-Computer) 02:05 PM QueueTest) mono QueueTest.exe
And the output:
Producer #1 put: 0, size : 1
Consumer #1 got: 0, size : 0
Producer #1 put: 1, size : 1
Producer #1 put: 2, size : 2
Consumer #1 got: 1, size : 1
Producer #1 put: 3, size : 2
Producer #1 put: 4, size : 3
Consumer #1 got: 2, size : 2
Producer #1 put: 5, size : 3
Producer #1 put: 6, size : 4
Producer #1 put: 7, size : 5
Consumer #1 got: 3, size : 4
Producer #1 put: 8, size : 5
Consumer #1 got: 4, size : 4
Producer #1 put: 9, size : 5
Consumer #1 got: 5, size : 4
Producer #1 put: 10, size : 5
Consumer #1 got: 6, size : 4
Producer #1 put: 11, size : 5
Consumer #1 got: 7, size : 4
Producer #1 put: 12, size : 5
Consumer #1 got: 8, size : 4
Producer #1 put: 13, size : 5
Consumer #1 got: 9, size : 4
Producer #1 put: 14, size : 5
Consumer #1 got: 10, size : 4
Producer #1 put: 15, size : 5
Consumer #1 got: 11, size : 4
Producer #1 put: 16, size : 5
Consumer #1 got: 12, size : 4
Producer #1 put: 17, size : 5
Consumer #1 got: 13, size : 4
Producer #1 put: 18, size : 5
Consumer #1 got: 14, size : 4
Producer #1 put: 19, size : 5
Consumer #1 got: 15, size : 4
Consumer #1 got: 16, size : 3
Consumer #1 got: 17, size : 2
Consumer #1 got: 18, size : 1
Consumer #1 got: 19, size : 0
Notice how the queue never fills up beyond the specified limit despite the fact that new items are being produced faster than they are consumed.
Still loving Mono/C#
No comments
Jump to comment form | comments rss [?] | trackback uri [?]