c#中多线程同步解决方案
1. Lock(object) 对需要同步的代码块加锁;
2. Monitor Class
3. ReaderWriterLock Class
4. Mutex Class
5. Semaphore
6. Event
这次我主要说一下 Lock 和 Monitor。对于Lock 想必有一定多线程编程经验的程序员都会很熟悉,看名字就知道大概是什么意思了。Lock 就是一把锁,举个很不雅得例子。比如说我们去上WC,当你进去后就要把门锁住,后来的人只能等你方便完了才能进去。
public void GoWC(Person p)
{
lock (lockFlag)
{
Console.WriteLine("Begin");
Console.WriteLine("End");
}
}
Lock使用起来非常方便,有一点需要注意就是你同步的对象最好是private或private static,因为如果这个同步对象是public或internal,就有可能被其他程序中其他部分的代码获得,这样的话你的lock就失去的作用,也就是说这个WC的钥匙只能有一把,只有进了WC的人才能获得,其他等待的人是没有办法获得的。
另一个常用的解决方案是使用Monitor class。 monitor class 和lock其实本身没有什么区别,这难免会让人觉得费解,其实不然。对于使用lock关键字来说经常会发生一种让人非常郁闷的事情“Deadlock”,当personA拥有resourceA还需要ResourceB才能完成任务,而PersonB拥有ResourceB还需要ResourceA才能完成任务时,就会发生死锁,而Lock关键字没有任何的超时机制。
对于Monitor Class 则不同,Monitor Class中有一个TryEnter的方法,参数列表中可以指定超时时间。
Code
public void GoWC(Person p)
{
Monitor.TryEnter(lockFlag, 100);
try
{
Console.WriteLine("Begin");
。。。。。
Console.WriteLine("End");
}
finally
{
Monitor.Exit(lockFlag);
}
有的时候也许当一个线程进入一个同步区域后,又在等待另一个获取资源。对于这样的情况,我们可以使用Monitor类的Wait()操作让它先释放锁,让其它线程进入,等待可以获得资源时再重新进入同步区域:
static void Main(string[] args)
{
Thread threadPing = new Thread(new ThreadStart(ThreadPingProc));
Thread threadPong = new Thread(new ThreadStart(ThreadPongProc));
threadPing.Start();
threadPong.Start();
threadPing.Join();
threadPong.Join();
Console.ReadLine();
}
public static void ThreadPingProc()
{
Console.WriteLine("ThreadPong : Hello!");
lock (ball)
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("ThreadPong: Pong");
Monitor.Pulse(ball);
Monitor.Wait(ball);
}
}
}
public static void ThreadPongProc()
{
Console.WriteLine("ThreadPing : Hello!");
lock (ball)
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("ThreadPing: Ping");
Monitor.Pulse(ball);
Monitor.Wait(ball);
}
}
}
}
(这里使用了《C#和.NET2.0实战(中文版)》p108的代码)
结果如下:
ThreadPing : Hello!
ThreadPing: Ping
ThreadPong : Hello!
ThreadPong: Pong
ThreadPing: Ping
ThreadPong: Pong
ThreadPing: Ping
ThreadPong: Pong
ThreadPing: Ping
ThreadPong: Pong
ThreadPing: Ping
ThreadPong: Pong