I'm trying to understand how to use semaphores while working with threads.
I have 2 threads that uses the same resource - an ArrayList
.
One method adds a random temperature to the list, the other method calculate the average temperature of the list.
How do I use semaphore's methods Wait
and Release
in this context?
and how can I control that my thread that calculate the average temperature starts after something is added to my list.
This is some of my code:
class Temperature
{
private static Random random = new Random();
private static ArrayList buffer = new ArrayList();
static SemaphoreSlim e, b;
public static void Main (string[] args)
{
e = new SemaphoreSlim(6); //how will this work?
b = new SemaphoreSlim(1);
Thread t1 = new Thread (Add);
t1.Start ();
Thread t2 = new Thread (Average);
t2.Start ();
}
public static void Add()
{
int temperature;
for (int i=0; i<50; i++)
{
temperature = random.Next (36, 42);
Console.WriteLine ("Temperature added to buffer: " + temperature);
b.Wait ();
e.Wait ();
buffer.Add(temperature);
b.Release ();
Thread.Sleep (50);
}
}
}
You need two things here.
You can do the one with a semaphore, although a lock or Monitor is more appropriate. The other really requires an event, probably AutoResetEvent
.
private static Random random = new Random();
private static ArrayList buffer = new ArrayList();
static SemaphoreSlim BufferLock = new SemaphoreSlim(1);
static AutoResetEvent ItemAdded = new AutoResetEvent(false);
public static void Main (string[] args)
{
BufferLock.Wait(); // initially acquire the semaphore.
Thread t1 = new Thread (Add);
t1.Start ();
Thread t2 = new Thread (Average);
t2.Start ();
// wait for adding thread to finish
t1.Wait();
}
public static void Add()
{
int temperature;
for (int i=0; i<50; i++)
{
temperature = random.Next (36, 42);
BufferLock.Wait();
buffer.Add(temperature);
ItemAdded.Set();
BufferLock.Release();
Console.WriteLine ("Temperature added to buffer: " + temperature);
Thread.Sleep (50);
}
}
public static void Average()
{
while (true)
{
ItemAdded.Wait(); // wait for item to be added
BufferLock.Wait();
ComputeAverage(); // however you want to do this
BufferLock.Release();
}
}
If you want to make sure that the last Average is computed, you'll have to wait on t2
. Of course, you'll need a way to tell the thread to exit. Look into Cancellation.
You really shouldn't be using ArrayList
. List< int > would be a much better choice. The only reason ever to use ArrayList
is when you're writing code for .NET versions prior to 2.0, or when you're supporting very old code.
You could replace the AutoResetEvent
with a Semaphore
to simulate the event notification, but doing so is a bit of a kludge and will require very careful coding to get right. I certainly wouldn't want to do it that way.