Introduction
The semaphore class works similar to the
Monitor and Mutex class but lets you set a limit on how many threads have access
to a critical section. It's often described as a nightclub (the semaphore) where
the visitors (threads) stands in a queue outside the nightclub waiting for
someone to leave in order to gain entrance.
A critical
section is
a piece of code that accesses a
shared resource (data structure or device)
but the condition is that only one thread can enter in this section in a time.
Introducing
: System.Threading.Semaphore
System.Threading.Semaphore
provide all the method and property which are require to implement Semaphore.
To use a semaphore in C#, you
first need to instantiate an instance of a Semaphore object. The constructor,
at a minimum, takes two parameters. The first is the number of resource slots
initially available when the object is instantiated. The second parameter is
the maximum number of slots available. If you want to reserve some slots for
the calling thread, you can do so by making the first parameter smaller than the
second. To reserve all slots for new threads, you should make both parameters
the same.
After you instantiated your Semaphore object,
you simply need to call the WaitOne() method when entering an area of code that
you want restricted to a certain number of threads. When processing finishes,
call the Release() method to release the slot back to the pool.
The count on a semaphore is decremented each
time a thread enters the semaphore, and incremented when a thread releases the
semaphore. When the count is zero, subsequent requests block until other threads
release the semaphore. When all threads have released the semaphore, the count
is at the maximum value specified when the semaphore was created.
Creating a new semaphore is accomplished
through one of the existing constructors:
- Semaphore(Int32,Int32)
: Initializes a new instance of the Semaphore class,
specifying the maximum number of concurrent entries and optionally
reserving some entries.
- Semaphore(Int32,Int32,String)
: Initializes a new instance of the Semaphore class, specifying the
maximum number of concurrent entries, optionally reserving some entries
for the calling thread, and optionally specifying the name of a system
semaphore object.
- Semaphore(Int32,Int32,String,Boolean)
: Initializes a new instance of the Semaphore class, specifying the
maximum number of concurrent entries, optionally reserving some entries
for the calling thread, optionally specifying the name of a system
semaphore object, and specifying a variable that receives a value
indicating whether a new system semaphore was created.
- Semaphore(Int32,Int32,String,Boolean,SemaphoreSecurity)
: Initializes a new instance of the Semaphore class, specifying the
maximum number of concurrent entries, optionally reserving some entries
for the calling thread, optionally specifying the name of a system
semaphore object, specifying a variable that receives a value indicating
whether a new system semaphore was created, and specifying security access
control for the system semaphore.
Using the code
using
System;
using
System.Threading;
namespace
threadingSemaphore
{
class Akshay
{
static
Thread[] threads = new
Thread[10];
static
Semaphore sem = new
Semaphore(3, 3);
static void
C_sharpcorner()
{
Console.WriteLine("{0}
is waiting in line...", Thread.CurrentThread.Name);
sem.WaitOne();
Console.WriteLine("{0}
enters the C_sharpcorner.com!", Thread.CurrentThread.Name);
Thread.Sleep(300);
Console.WriteLine("{0}
is leaving the C_sharpcorner.com", Thread.CurrentThread.Name);
sem.Release();
}
static void
Main(string[] args)
{
for (int
i = 0; i < 10; i++)
{
threads[i] = new
Thread(C_sharpcorner);
threads[i].Name = "thread_" +
i;
threads[i].Start();
}
Console.Read();
}
}
}
Output
Some more
important facts about Semaphore
- There is no guaranteed order, such as FIFO
or LIFO, in which blocked threads enter the semaphore.
- The Semaphore
class does not enforce thread identity on calls to WaitOne() or Release().
It is the programmer's responsibility to ensure that threads do not release
the semaphore too many times.
- For example, suppose a semaphore has a
maximum count of two, and that thread A and thread B both enter the
semaphore. If a programming error in thread B causes it to call Release
twice, both calls succeed. The count on the semaphore is full, and when
thread A eventually calls Release, a SemaphoreFullException is thrown.
- Semaphores are of two types: local
semaphores and named system semaphores.
- If you create a
Semaphore object using a constructor that accepts a name, it is
associated with an operating-system semaphore of that name.
- Named system semaphores are visible
throughout the operating system, and can be used to synchronize the
activities of processes.
- You can create multiple
Semaphore objects that represent the same
named system semaphore, and you can use the OpenExisting() method to open an
existing named system semaphore.
- A local semaphore exists only within your
process. It can be used by any thread in your process that has a reference
to the local Semaphore object.
- Each Semaphore
object is a separate local semaphore.