1). 在类的声明中,添加
System.Runtime.Remoting.Contexts.SynchronizationAttribute属性。 2). 继承至System.ContextBoundObject 需要注意的是,要实现上述机制,类必须继承至
System.ContextBoundObject,换句话说,类必须是上下文绑定的。 一个示范类代码如下:
Code [System.Runtime.Remoting.Contexts.Synchronization] public class SynchronizedClass : System.ContextBoundObject { }
八、MethodImplAttribute
如果临界区是跨越整个方法的,也就是说,整个方法内部的代码都需要上锁的话,使用MethodImplAttribute属性会更简单一些。这样就不用在方法内部加锁了,只需要在方法上面加上
[MethodImpl(MethodImplOptions.Synchronized)] 就可以了,MehthodImpl和MethodImplOptions都在命名空间
System.Runtime.CompilerServices 里面。但要注意这个属性会使整个方法加锁,
直到方法返回,才释放锁。因此,使用上不太灵活。如果要提前释放锁,则应该使用Monitor或lock。我们来看一个例子:
Code [MethodImpl(MethodImplOptions.Synchronized)] public void DoSomeWorkSync() { Console.WriteLine( \ DoSomeWorkSync() -- Lock held by Thread \ + Thread.CurrentThread.GetHashCode()); Thread.Sleep( 1000 ); Console.WriteLine( \ DoSomeWorkSync() -- Lock released by Thread \ +
Thread.CurrentThread.GetHashCode()); }
public void DoSomeWorkNoSync() {
Console.WriteLine( \ DoSomeWorkNoSync() -- Entered Thread is \ +
Thread.CurrentThread.GetHashCode()); Thread.Sleep( 1000 );
Console.WriteLine( \ DoSomeWorkNoSync() -- Leaving Thread is \ +
Thread.CurrentThread.GetHashCode()); }
[STAThread]
static void Main( string [] args) {
MethodImplAttr testObj = new MethodImplAttr();
Thread t1 = new Thread( new ThreadStart(testObj.DoSomeWorkNoSync));
Thread t2 = new Thread( new ThreadStart(testObj.DoSomeWorkNoSync)); t1.Start(); t2.Start();
Thread t3 = new Thread( new ThreadStart(testObj.DoSomeWorkSync));
Thread t4 = new Thread( new ThreadStart(testObj.DoSomeWorkSync)); t3.Start(); t4.Start();
Console.ReadLine(); }
这里,我们有两个方法,我们可以对比一下,一个是加了属性MethodImpl的DoSomeWorkSync(),一个是没加的DoSomeWorkNoSync()。在方法中Sleep(1000)是为了在第一个线程还在方法中时,第二个线程能够有足够的时间进来。对每个方法分别起了两个线程,我们先来看一下结果:
可以看出,对于线程1和2,也就是调用没有加属性的方法的线程,当线程2进入方法后,还没有离开,线程1有进来了,这就是说,方法没有同步。我们再来看看线程3和4,当线程3进来后,方法被锁,直到线程3释放了锁以后,线程4才进来。
九、同步事件和等待句柄
用lock和Monitor可以很好地起到线程同步的作用,但它们无法实现线程之间传递事件。如果要实现线程同步的同时,线程之间还要有交互,就要用到同步事件。同步事件是有两个状态(终止和非终止)的对象,它可以用来激活和挂起线程。
同步事件有两种:AutoResetEvent和 ManualResetEvent。它们之间唯一不同的地方就是在激活线程之后,状态是否自动由终止变为非终止。AutoResetEvent自动变为非终止,就是说一个AutoResetEvent只能激活一个线程。而ManualResetEvent要等到它的Reset方法被调用,状态才变为非终止,在这之前,ManualResetEvent可以激活任意多个线程。
可以调用WaitOne、WaitAny或WaitAll来使线程等待事件。它们之间的区别可以查看MSDN。当调用事件的 Set方法时,事件将变为终止状态,等待的线程被唤醒。
来看一个例子,这个例子是MSDN上的。因为事件只用于一个线程的激活,所以使用 AutoResetEvent 或 ManualResetEvent 类都可以。
Code
static AutoResetEvent autoEvent;
static void DoWork() {
Console.WriteLine(\worker thread started, now waiting on event\);
autoEvent.WaitOne();
Console.WriteLine(\worker thread reactivated, now exiting\); }
[STAThread]
static void Main(string[] args) {
autoEvent = new AutoResetEvent(false);
Console.WriteLine(\starting worker thread\); Thread t = new Thread(new ThreadStart(DoWork)); t.Start();
Console.WriteLine(\for 1 second\); Thread.Sleep(1000);
Console.WriteLine(\\); autoEvent.Set();
Console.ReadLine(); }

