LA.NET [EN]

May 17

In the previous post we’ve seen several concepts associated with semaphore usage. In this post we’re going to see some code that shows how to use this synchronization kernel object. Creating a new semaphore is accomplished through one of the existing constructors:

public Semaphore(int initialCount, int maximumCount);
public Semaphore(int initialCount, int maximumCount, string name);
public Semaphore(int initialCount, int maximumCount, string name, out bool createdNew);
public Semaphore(int initialCount, int maximumCount, string name, out bool createdNew, SemaphoreSecurity semaphoreSecurity);

Whenever you create a semaphore, you need to initialize its initial and maximum allowed count. These values might be a little confusing,so I think it would be wise to describe them a little better before going on…initialCount is used for initializing the internal counter used by the sempahore. On the other hand,maximumCount defines the maximum number of threads that can acquire the resource protected by the semaphore without blocking (after maximumCount has been reached, all threads will block whenever they try to acquire the protected resource). Passing different values for these properties is the same thing as having the current thread call WaitOne maximumCount-initialCount times. Take a look at the following instantiations:

(1) var semaphore = new Semaphore(0, 2);
(2) var semaphore = new Semaphore(2, 2);

On (1), the next thread that performs a take (ie, that calls WaitOne) over the semaphore will block; on the other hand, (2) lets you call WaitOne twice before blocking the thread that performs the next call.

Since there isn’t the concept of ownership, nothing prevents you from calling Release from a thread that didn’t acquire the semaphore. You can even use the overload that accepts an integer that indicates the number of times you’re releasing the semaphore. In practice, this means that Release bumps up the internal counter, allowing other threads that were blocked to awake up. You need to be sure that you don’t go over the maximum value allowed (passed to the semaphore through the constructor) or you’ll get an exception.

Everything we’ve said about *named* mutexes is also true for semaphores (ie, when you create a named semaphore, you might be getting a new semaphore or an existing semaphore – you need to check the createdNew parameter to see what has happened after that call). Ok, I guess it’s time to take a look at some code. The following is a possible implementation of a concurrent stack where we allow several consumers and producers to add and remove elements concurrently from the queue. Here is the code*:

class ConcurrentStack<T> {
    private Stack<T> _stack = new Stack<T>();
    private Mutex _lock = new Mutex();
    private Semaphore _producer;
    private Semaphore _consumer;
    public ConcurrentStack(Int32 maxCapacity) {
        _producer = new Semaphore(maxCapacity, maxCapacity);
        _consumer = new Semaphore(0, maxCapacity);
    }
    public T Pop() {
        _consumer.WaitOne();
        T element;
        _lock.WaitOne();
        try {
            element = _stack.Pop();
        }
        finally {
            _lock.ReleaseMutex();
        }
        _producer.Release();
        return element;
    }
    public void Push(T element) {
        _producer.WaitOne();
        _lock.WaitOne();
        try {
            _stack.Push(element);
        }
        finally {
            _lock.ReleaseMutex();
        }
        _consumer.Release();
    }
}

As you can see, we’re not using the semaphore for achieving mutual exclusion (that’s the job of the mutex, which is there for ensuring proper mutual exclusion for the queue access). In this case, we’re using semaphores for controlling the number of pops and pushes that can happen at a specific time. As you can see, there are two semaphores: one for consumers (which control the number of concurrent pop instructions that can happened) and another for producers (that control entry on the Push method). The previous code ensures that a thread that tries to add an item to a stack that has maxCapacity elements is blocked (the same happens for a thread that tries to remove an element from an empty stack).

Notice that acquiring and releasing operations are performed in different methods (compare this behavior with the mutex’s behavior!). Whenever we pop an element, we take one from the consumer’s semaphore and then we call Release over the producer’s semaphore, leading to a possible wake of a thread that might have been previously blocked. The inverse principle is followed by the Pop method.

Now we can simply create several consumer and producer threads. Here’s some code that does that:

var stack = new ConcurrentStack<Int32>(2);
var consumerThread1 = new Thread( () => { Console.WriteLine( stack.Pop() ); });
var consumerThread2 = new Thread( () => { Console.WriteLine( stack.Pop() ); });
var producerThread1 = new Thread(num => { stack.Push((Int32)num);});
var producerThread2 = new Thread(num => { stack.Push((Int32)num); });
consumerThread1.Start();
consumerThread2.Start();
producerThread1.Start(2);
producerThread2.Start(10);

If you run this program, you’ll notice that the consumers will block until there are elements on the stack. I think that this simple example is good for showing the things at which semaphores are good at. And that’s it for today. On the next post, we’ll be talking about auto and reset events. Keep tuned!

* heavily influenced by Joe Duffy’s Concurrent Programming on Windows excellent book.

5 comments so far

  1. MypeInope
    1:19 am - 6-24-2009

    Hey guys,

    I found a website that actually worked to get a free IPod Touch! It should work for you too, it takes a few weeks to get it but hey it”s free!

    http://absolutelyfreestuff.info/ipod.php – Click Here to get yours.

  2. rirmhobby
    11:10 am - 10-18-2009

    http://verifiedfile.com/images/soundsbox.png

    Attention All Music Lovers

    Face it – Itunes.com & Amazon are tooooo Darn Expensive http://verifiedfile.com/images/smile.gif

    Just a short note to let you know that SoundsBox.com Buy MP3 Music website has re-done their website and are now offering music at 14 cents per song.

    Purchase & Download Full Albums of Michael Jackson, Eminem, Linkin Park, Madonna, etc., for just $1 dollar. It makes no sense to pay Itunes $1 per song when you can get the full album!

    Advantanges of SoundsBox.com Mp3 Download Portal
    ** Listen to 30 Second Sample of Music Before Purchase.
    ** All Music is in MP3 Format – NO DRM. Play on Ipods & Iphones!
    ** Instant Download Favorite Mp3 Music
    ** Top 10 Music for Free just for Registering.
    ** All Music Costs 14Cents Per Song (Itunes cost over $1)

    http://verifiedfile.com/images/soundsbox.jpg

  3. SmesseSoave
    2:19 am - 10-22-2009

    Hey People

    I”m looking to learn Krav Maga. I have some MMA experience and I”m wondering if Krav Maga is right for me. I”m looking for a mix of Self Defense and a Krav Maga Workout

    I need some expert advice here

    cheers

    Michael

  4. kalyan
    5:53 pm - 11-17-2009

    excellent example , thanks

  5. Squadron
    8:44 am - 1-7-2010

    Hello everyone.

    My name is Jonathan, currently based in belgium,
    I am both English and French native language,
    just wanted to say hello and Looking forward to sharing information with all of you:-)

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>