在C#中实现线程的同步有几种方法:lock、Mutex、Monitor、Semaphore、Interlocked和ReaderWriterLock等。
1.lock同步
2.Monitor类
针对上面的代码,如果使用Monitor类来同步的话,互斥同步,使用如下
实际上是相当于:
我们知道在绝大多数情况下finally中的代码块一定会被执行,这样确保了即使同步代码出现了异常也仍能释放同步锁。
Monitor类出了Enter()和Exit()方法之外,还有Wait()和Pulse()方法。
Wait()方法是临时释放当前活得的锁,并使当前对象处于阻塞状态,
Pulse()方法是通知处于等待状态的对象可以准备就绪了,它一会就会释放锁。
3.ReaderWriterLock
ReaderWriterLock支持单个写线程和多个读线程的锁。在任一特定时刻允许多个线程同时进行读操作或者一个线程进行写操作,使用ReaderWriterLock来进行读写同步比使用监视的方式(如Monitor)效率要高。
AcquireReaderLock(TimeSpan),超时值读线程锁,ReleaseReaderLock()减少读锁计数器,释放锁
AcquireWriterLock(TimeSpan)超时值写线程锁,ReleaseWriterLock()减少写锁计数器,释放锁
WaitHandle
WaitHandle类是一个抽线类,有多个类直接或者间接继承自WaitHandle类,类图如下:
在WaitHandle类中SignalAndWait、WaitAll、WaitAny及WaitOne这几个方法都有重载形式,其中除WaitOne之外都是静态的。WaitHandle方法常用作同步对象的基类。WaitHandle对象通知其他的线程它需要对资源排他性的访问,其他的线程必须等待,直到WaitHandle不再使用资源和等待句柄没有被使用。
WaitHandle方法有多个Wait的方法,这些方法的区别如下:
WaitAll:等待指定数组中的所有元素收到信号。
WaitAny:等待指定数组中的任一元素收到信号。
WaitOne:当在派生类中重写时,阻塞当前线程,直到当前的 WaitHandle 收到信号。
这些wait方法阻塞线程直到一个或者更多的同步对象收到信号。
下面的是一个MSDN中的例子,讲的是一个计算过程,最终的计算结果为第一项+第二项+第三项,在计算第一、二、三项时需要使用基数来进行计算。在代码中使用了线程池也就是ThreadPool来操作,这里面涉及到计算的顺序的先后问题,通过WaitHandle及其子类可以很好地解决这个问题。
代码如下:
程序的运行结果如下:
Result = 0.355650523270459.
Result = 0.125205692112756.