65.9K
CodeProject 正在变化。 阅读更多。
Home

使用信号量进行线程同步

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (5投票s)

2011年11月19日

CPOL

1分钟阅读

viewsIcon

56624

downloadIcon

1638

介绍信号量与监视器的对比

Semaphore.JPG

引言

信号量是一种同步技术,我们可以控制访问资源的线程数量。在锁/互斥锁中,一次只有一个线程可以访问资源。但信号量允许多个线程同时访问同一资源。我们可以限制可以访问相同资源的线程数量。 在本文中,我展示了三种不同的访问资源的方法。

  • 第1种:无同步
  • 第2种:使用Monitor同步
  • 第3种:使用信号量同步

Using the Code

无同步

在没有同步的情况下,所有线程同时运行并同时执行相同的代码。对可以访问它的线程数量没有限制。 以下是代码

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());
}

使用Monitor同步

使用Monitor类进行同步时,一次只有一个线程可以访问相同的资源。线程同时运行,但一次只能访问一段代码。对线程有限制,以便只有一个线程可以访问特定的代码块。

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());
}

使用信号量同步

在与semaphore类同步时,我们可以允许多个线程访问相同的代码块。实际上,我们可以指定可以同时访问相同代码块的线程数量。

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());
}

测试代码

可以轻松测试信号量。运行应用程序并逐个按下所有按钮,查看信号量控制同时执行某些代码块的线程总数的效应。信号量是一种基于资源的同步技术,也是一种系统范围的同步资源。

历史

  • 2011年11月19日:初始发布
© . All rights reserved.