多线程同步与委托,方法的异步调用

线程同步即线程间对于CPU资源的协调,一次只有一个线程占用资源。进行线程同步的方法:

1.线程1调用方法,线程2在运行结束后调用Resume()方法唤醒工作线程,此方法需借助Sleep()方法协调时间,不灵活。容易出问题,比如线程1还没有Suspend(),线程2就Resume();或者后台进程还未运行,前台进程就结束了。

2.使用System.Threading.Monitor的Lock语句,调整Lock的颗粒度,即可得到想要的线程工作顺序(两个线程交替输出、顺位输出)。通过创建一个对象,实现对上锁(Enter())开锁(Exit())的目的,对象或者是object类型或是type类型。上述方法无法指定线程间的工作顺序,需要引入信号的概念来实现,原理类似1中的Suspend()和Resume()方法。Monitor中,有Wait()和Pulse()方法。原理很简单,线程1用Wait()方法等待线程2,线程2做完工作用Pulse()方法知会线程1,“我做完了”,线程1继续执行自己的下一步。

3.使用System.Threading.WaitHandle旗下的Mutex类可以帮助简化上锁的过程,它可以替代为了上锁而创建的锁对象。

委托用于调用一个方法,通过委托进行异步调用时,往往是从线程池抓取线程执行,随用随取。运用BeginInvoke()和EndInvoke()的方法实现。以下为一个示例:两个线程运行,主线程在static void Main里面,线程池线程执行Calculator方法里的程序。

class Program
    {
        public delegate int AddDelegate(int x,int y);
        static void Main(string[] args)
        {
            Console.WriteLine("Task started!");
            Thread.CurrentThread.Name = "Main Thread";

            Calculator cal = new Calculator();
            AddDelegate del = new AddDelegate(cal.Add);//异步调用方法Add
            AsyncCallback callback = new AsyncCallback(GetReturn);//不再使用EndIncoke,而使用回调函数,当异步方法结束后自动打印结果
            string data = "吃麻辣烫";
            IAsyncResult asyresult = del.BeginInvoke(2, 5, callback, data);
           
            Thread.Sleep(TimeSpan.FromSeconds(2));
            Console.WriteLine("主线程干活");

            //int result = del.EndInvoke(asyresult);//通过IAsyncResult接口得到结果。        
            Console.WriteLine("the current thread is {0} ",Thread.CurrentThread.Name);
            
            Console.ReadKey();

        }

        static void GetReturn(IAsyncResult asyresult)
        {
            AsyncResult result = (AsyncResult)asyresult;//将IAsyncResult类型转换成实际的类型AsyncResult,才能使用AsyncDelegate
            AddDelegate del = (AddDelegate)result.AsyncDelegate;
            //AddDelegate del = (AddDelegate)result.AsyncDelegate;
            string data = (string)result.AsyncState;//get the object of BeginInvoke
            int rtn = del.EndInvoke(asyresult);
            Console.WriteLine("the result is {0}; Data: {1}", rtn,data);
        }

        public class Calculator
        {   
           
            public int Add(int x,int y)
            {
                Console.WriteLine("Method Invoked");
                if (Thread.CurrentThread.IsThreadPoolThread)
                {
                    Thread.CurrentThread.Name = "Pool Thread";

                }
                Thread.Sleep(TimeSpan.FromSeconds(3));//线程池方法持续3s
                Console.WriteLine("the current thread is {0}, Method complete!",Thread.CurrentThread.Name);           
                int result = x + y;
                return result;
            }
        }

        //int result = del.EndInvoke(asyresult)在第26行,紧接着beginInvoke,则程序全程消耗7s。
        //如果该语句在30行,当主线程工作时间大于线程池,线程池先工作,反之,主线程先工作,总工作时长为两者最大值;
    }

4. 发布者和订阅者

发布者的事件C通过委托绑定订阅者中的方法A,并在其内通过一个方法B激活事件C,从而执行方法A。

发布者和订阅者之间的关系是松耦合的,大多数情况下,它不关心订阅者执行的结果,除非异常处理时,需要及时止损。

5.Observer设计模式

这里的例子就是热水壶烧水,在到了快到100度的时候,显示器提示当前温度,到了100度是,显示烧开了。观察者是显示器,被观察者是热水壶。

推模式:将热水壶的温度变量封装为data(e),通过Notify()方法,使得显示器的值实时更新

拉模式:直接将显示器向下转换,作为obj传递出去。这时为了访问温度,需要为温度变量创建一个公共属性,使得在程序中其它位置也可以修改温度变量,增加了风险。

推模式就像是通过密码新传递情报,而拉模式就像是特工本人出面口头传递,显然暴露的可能性更大。

这两种模式都通过Notify()方法,传递给Update()方法,后者从属于观察者,一手e,一手obj,这就是事件的来源了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值