The code below returns the following output:
Semaphore sema = new Semaphore(5,5,"sema_1");
for (int i = 0; i < 10; i++)
{
    ThreadPool.QueueUserWorkItem(delegate(object state)
    {
        sema.WaitOne();
        Console.WriteLine(" = " + i);
        sema.Release();
    });
}
And just by adding the int j = i it completely changes the output to what I was expecting, which is the proper response reaching the limit of the Semaphore:
Semaphore sema = new Semaphore(5,5,"sema_1");
for (int i = 0; i < 10; i++)
{
    int j = i;
    ThreadPool.QueueUserWorkItem(delegate(object state)
    {
        sema.WaitOne();
        Console.WriteLine(" = " + j);
        sema.Release();
    });
}


