使用信号量进行线程同步





4.00/5 (5投票s)
介绍信号量与监视器的对比

引言
信号量是一种同步技术,我们可以控制访问资源的线程数量。在锁/互斥锁中,一次只有一个线程可以访问资源。但信号量允许多个线程同时访问同一资源。我们可以限制可以访问相同资源的线程数量。 在本文中,我展示了三种不同的访问资源的方法。
- 第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日:初始发布