Click here to Skip to main content
15,887,477 members
Articles / General Programming / Threads
Article

Thread Synchronization with Semaphore

Rate me:
Please Sign up or sign in to vote.
4.00/5 (5 votes)
19 Nov 2011CPOL1 min read 55K   1.6K   31   5
An introduction to semaphore in contrast to Monitor
Semaphore.JPG

Introduction

Semaphore is a synchronization technique where we can control number of threads to access a resource. In lock/Mutex, only one thread can access resources at a time. But Semaphore allows multiple threads to access the same resource at a time. We can limit the number of threads that can access the same resources. In this article, I have shown three different ways to access resources.

  • No-1. No Synchronization
  • No-2. Synchronization with Monitor
  • No-3. Synchronization with Semaphore

Using the Code

No Synchronization

With no synchronization, all threads run simultaneously and execute the same piece of code simultaneously. There is no restriction on how many threads can access it. Following is the code:

C#
private void btnNoSync_Click(object sender, EventArgs e)
{
            listBox1.Items.Add("== No Synchronization ===========");
            int TotalThread = 5;
            Thread[] Threads = new Thread[TotalThread];
            for (int i = 0; i < TotalThread; i++)
            {
                Threads[i] = new Thread(new ThreadStart(AccessCode));
                Threads[i].IsBackground = true;
                Threads[i].Start();
            } 
}
public void AccessCode()
{
   listBox1.BeginInvoke(new ParameterizedThreadStart(UpdateUI), new object[] 
       {"Thread ID : " + Thread.CurrentThread.ManagedThreadId.ToString() + ": Entered" }
                        );
   Thread.Sleep(500);
   listBox1.BeginInvoke(new ParameterizedThreadStart(UpdateUI), new object[]  
       { "Thread ID : " + Thread.CurrentThread.ManagedThreadId.ToString() + " : Exit" }
                        );
}
 
// Following code is used to update UI
public void UpdateUI(object objOutput)
{
   listBox1.Items.Add(objOutput.ToString());
}

Synchronization with Monitor

Synchronization with monitor class, only one thread can access the same resource at a time. Thread is run simultaneously but it can access the block of code one at a time. There is a restriction on thread so that only a single thread can access a particular code block.

C#
private void buttonMonitor_Click(object sender, EventArgs e)
{
            listBox1.Items.Add("== Using Monitor =============");
            int TotalThread = 5;
            Thread[] Threads = new Thread[TotalThread];
            for (int i = 0; i < TotalThread; i++)
            {
                Threads[i] = new Thread(new ThreadStart(AccessCodeWithMonitor));
                Threads[i].IsBackground = true;
                Threads[i].Start();
            }
} 
private void AccessCodeWithMonitor()
{
            Monitor.Enter(this);
            try
            {
                listBox1.BeginInvoke(new ParameterizedThreadStart(UpdateUI), new object[] 
                     { "Thread ID : " + 
		    Thread.CurrentThread.ManagedThreadId.ToString() + " : Entered" });
                Thread.Sleep(500);
                listBox1.BeginInvoke(new ParameterizedThreadStart(UpdateUI), new object[] 
                     { "Thread ID : " + 
		    Thread.CurrentThread.ManagedThreadId.ToString() + " : Exit" });
            }
            finally
            {
                Monitor.Exit(this);
            }
}
private void UpdateUI(object objOutput)
{
   listBox1.Items.Add(objOutput.ToString());
}

Synchronization with Semaphore

In synchronization with semaphore class, we can allow more than one thread to access the same block of code. Actually, we can specify how many threads can access the same block of code at the same time.

C#
private void btnSemaphore_Click(object sender, EventArgs e)
{
            listBox1.Items.Add("== Using Semaphore =============");
            int TotalThread = 5;
            int SemaphoreCount = 3;
            Thread[] Threads = new Thread[TotalThread];
            Semaphore Sema = new Semaphore(SemaphoreCount, SemaphoreCount);
            for (int i = 0; i < TotalThread; i++)
            {
                Threads[i] = new Thread(new ParameterizedThreadStart
				(AccessCodewithSemaphore));
                Threads[i].IsBackground = true;
                Threads[i].Start(Sema);
            }
}
public void AccessCodewithSemaphore(object objSemaphore)
{
            bool IsComplete = false;
            Semaphore l_SemaPhore = (Semaphore)objSemaphore;
            while (!IsComplete)
            {
                if (l_SemaPhore.WaitOne(200, false))
                {
                  try
                  {
                    listBox1.BeginInvoke(new ParameterizedThreadStart(UpdateUI), 
					new object[] 
                      {"Thread ID : " + 
		    Thread.CurrentThread.ManagedThreadId.ToString() + " : Entered" });
                    Thread.Sleep(500);
                   }
                   finally
                   {
                     l_SemaPhore.Release();
                     listBox1.BeginInvoke(new ParameterizedThreadStart(UpdateUI), 
					new object[] 
                       { "Thread ID : " + 
		     Thread.CurrentThread.ManagedThreadId.ToString() + " : Exit" });
                     IsComplete = true;
                    }
                }
                else
                {
                  listBox1.BeginInvoke(new ParameterizedThreadStart(UpdateUI), 
					new object[] 
                  {"Thread ID :"+Thread.CurrentThread.ManagedThreadId.ToString() + 
				": Waiting To enter"});
                }
            }
} 
public void UpdateUI(object objOutput)
{
   listBox1.Items.Add(objOutput.ToString());
}

Testing the Code

Semaphore can be tested easily. Run the application and press all buttons one by one and see the effect of semaphore which controls the total number of threads that can execute some block of code simultaneously. Semaphore is a resource based synchronization technique and its system wide synchronization resource.

History

  • 19th November, 2011: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Sapient Corporation Pvt. Ltd.
India India
Software Devloper sience 2006. Experience on VB 6.0,C# Web, Windows and Distributed application like WCF etc. Currently working at Sapient Corporation Pvt. Ltd

Comments and Discussions

 
QuestionMonitor.Wait and Monitor.Pulse Pin
supercat921-Nov-11 12:09
supercat921-Nov-11 12:09 
Although the Monitor class can be used to supply a basic mutex lock (i.e. allow different threads to have MUTually EXclusive access to something), it also has another very useful feature, which is somewhat like a semaphore. In many cases, a thread may acquire exclusive access to a resource, and then discover that it can't proceed until some other thread has done something to that resource. As a simple example, one may have one thread which expects to put items into a queue and another thread that expects to take items out of the queue and process them. If the second thread goes to fetch an item from the queue but there's nothing there, it shouldn't waste CPU time checking the queue unless or until there's reason to believe that someone else has added something to it.

Although such situations can be handled via semaphores, they can often be handled more efficiently using Monitor locks and the Monitor.Wait and Monitor.Pulse/PulseAll methods. Any comparison between monitor locks and semaphores should include those methods. Using them, one can make a monitor lock behave a lot like a semaphore. The biggest features that semaphores provide which monitor locks fundamentally cannot are:

  1. Semaphores can be used to synchronize threads running in different application domains. Monitor locks cannot.
  2. It's possible for a thread to wait on multiple semaphores (or other synchronization objects that inherit from WaitHandle), and "wake up" as soon as any of them gets signaled. By contrast, a thread can only wait on one monitor lock at a time.

If one needs these features, a semaphore can be good. Otherwise, monitor locks can be more efficient. Note that if one wants semaphore semantics but doesn't need the above features, it may be possible to use a SemaphoreSlim in newer versions of .net.
QuestionWhen one should use a semaphore? Pin
Paulo Zemek21-Nov-11 1:10
mvaPaulo Zemek21-Nov-11 1:10 
GeneralMy vote of 3 Pin
Sander Rossel19-Nov-11 3:15
professionalSander Rossel19-Nov-11 3:15 
GeneralRe: My vote of 3 Pin
Pranjit Kalita24-Nov-11 3:53
Pranjit Kalita24-Nov-11 3:53 
GeneralRe: My vote of 3 Pin
Sander Rossel24-Nov-11 7:05
professionalSander Rossel24-Nov-11 7:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.