同步构造(下)

同步构造()

 

前言

 

最近学习有点不走心啊,,不知道咋回事,接着写写昨天的没写完的内容吧,写的不好,大家大大指教.

 

 

 

CountdownEvent

 

.NET4.0提供了一个CountdownEvent,主要是让你等待多个线程.考虑下这样的场景:

 

有一个任务,3个人去做,你需要等这三个人都做完了才能继续下一步操作.案例如下:

   

 class ThreadTest
    {
        static CountdownEvent _countdown = new CountdownEvent(3);
 
        public static void MainThread()
        {
            new Thread(SayHello).Start("i am 1");
            new Thread(SayHello).Start("i am 2");
            new Thread(SayHello).Start("i am 3");
 
            _countdown.Wait();//阻塞,直到Singal被调用三次
            Console.WriteLine("所有的线程都已经运行完毕!");
 
 
        }
 
        static void SayHello(object obj)
        {
            Thread.Sleep(2000);
            Console.WriteLine(obj);
            _countdown.Signal();
        }
    }

 

注意在构造函数中我们传递了3,代表了我们要等待3个线程都结束.

 

 

 

Thread.RegisterWaitForSingleObject

 

如果你的应用中有大量的线程都在一个WaitHandle上花费了大量的时间,你可以通过线程池的ThreadPool.RegisterWaitForSingleObject方法来提高资源的利用率,这个方法接受一个委托,当这个WaitHandle调用Single方法后,方法的委托就会被执行了.

案例:

   

 class ThreadTest
    {
        static ManualResetEvent _starter = new ManualResetEvent(false);
 
        public static void MainThread()
        {
            RegisteredWaitHandle reg = ThreadPool.RegisterWaitForSingleObject(_starter,Go,"some data",-1,true);
            //在_starter上等待执行Go方法,-1代表永远不会超时
            //true代表只执行一遍,"some data"是传递的参数
 
            Thread.Sleep(5000);
            Console.WriteLine("Single is working...");
            _starter.Set();//唤醒等待的线程
            Console.ReadLine();
            reg.Unregister(_starter);//取消注册
        }
 
        static void Go(object obj,bool timeOut)
        {
            Console.WriteLine("started - "+obj);
            Console.WriteLine("ThreadID: "+Thread.CurrentThread.ManagedThreadId);
        }
    }
 

 

 

同步上下文

 

通过集成ContextBoundObject,并且加上Synchronization特性,CLR会自动的为你的操作加锁.案例:

    

//继承自ContextBoundObject,且加上Synchronization特性修饰
    [Synchronization]
    public class AutoLock : ContextBoundObject
    {
        public void Demo()
        {
            Console.WriteLine("Start...");
            Thread.Sleep(1000);
            Console.WriteLine("end");
        }
        //主线程
        public static void MainThread()
        {
            AutoLock safeInstance = new AutoLock();
            new Thread(safeInstance.Demo).Start();
            new Thread(safeInstance.Demo).Start();
            safeInstance.Demo();
        }
    }
 

如果你仔细看看输出的话,会发现输出很有意思.

 

CLR会确保一次只有一个线程可以执行safeInstance里面的代码,它会自动的创建一个同步对象,然后在每次调用方法或属性的时候都lock,从这个角度来看safeInstance是一个同步上下文.

 

但是它是怎么工作的,Synchronization特性和System.Runtime.Remoting.Context命名空间中存在着线索.

 

一个ContextBoundObject被认为是一个远程(“Remote”)对象,意味着所有的方法调用都可以被介入.当我们实例化AutoLock的时候,CLR实际尚返回了一个proxy对象,一个和AutoLock对象有着同样的方法,同样属性的proxy对象,在这里它扮演着中介的对象.这样就为自动加锁提供了介入的机会,在每一次方法调用上都会花费几微妙的时间来介入.

 

你可能认为下面的代码会和上面的一样,是一样的输出:

    

//继承自ContextBoundObject,且加上Synchronization特性修饰
    [Synchronization]
    public class AutoLock : ContextBoundObject
    {
        public void Demo()
        {
            Console.WriteLine("Start...");
            Thread.Sleep(1000);
            Console.WriteLine("end");
        }
        //主线程
        public static void MainThread()
        {
            AutoLock.RunTest();
        }
        public void Test()
        {
            new Thread(Demo).Start();
            new Thread(Demo).Start();
            new Thread(Demo).Start();
            Console.ReadLine();
        }
 
        public static void RunTest()
        {
            new AutoLock().Test();
        }
 
    }

 

分析:实际上我们会运行到CR方法这里,然后等待输入.

 

为啥?

 

因为CLR会确保一次只有一个线程能够执行AutoLock的代码,所以当主线程执行到CR方法的时候,就开始等待输入了.如果你按下Enter,代码就和上面的输出一样了.

 

 

 

总结

 

一点简单的同步构造就差不多说到这里了,因为本屌才疏学浅,没啥文化,如有错误请指出.

你可能感兴趣的:(C#)