用delegate实现.NET应用程序的同步函数的异步调用-.NET多线程编程实践之一

标题有点拗口,微软MSDN上是这样,而且也有它的道理,权直译过来。

在C++中有2种类型的线程:UI Thread和Worker Thread,前者是基于用户界面的有消息循环的线程、后者是没有用户界面的侧重于大时空运算的线程。直接调用Windows相关线程及同步对象的API即可。

在.NET framework进阶编程中,可以用基于delegate的方式来处理界面保持活动,而后台作大运算量或耗时的操作。


应用程序的需求是:点击一个按钮来刷新用户界面上某区域数据相关控件,其内容动态从web service上获取并填充到该控件,而不影响另一区域实时显示数据。


基本的作法是这样的:
1,定义2个delegate及分别对应的处理过程,注意返值和参数要一一对应。一个delegate代表的函数是顶层的异步调用,它会调用另外一个delegate,而另一个delegate代表的函数过程是GUI上会被刷新内容的控件相关的操作,通过System.Control.InvokeRequired判断调用线程与被调用控件是否在同一线程来显式运行System.Control.Invoke(明显地,它们位于不同线程,主要的目的是让同步调用可以复用这段函数代码)。需要特别注意的是,耗时操作要从System.Control.Invoke调用的delegate中分离开,否则跟单线程时效果没有区别,这一点让我困扰了不少时间。
2,定义一个回调函数,用于异步操作结束后的回调(而不是通过调用IAsyncResult接口的轮询方式),里面包括按钮控件的使能恢复和结束异步调用的EndInvoke显示调用。它是位于不同于调用线程的线程池中。

关键代码段如下:

        private void UpdateInquiry()
	{	//UI界面的更新放在这里(the other thread)
		
		//control operations on GUI such as clear, load data, fresh etc.  
		...
	}
		
        private delegate void crossThreadDelegate();
        private void UpdateInquiryContainer()	//此函数也可用于同步调用
        {
            //耗时操作一定要放在这里,不要包含在UpdateInquiry(UI界面的更新)中!!!(just like a worker thread as windows API)
            this._presenter.TimeConsumingOperation();

            if (treeListInquired.InvokeRequired)
            {
                crossThreadDelegate caller = new crossThreadDelegate(UpdateInquiry);
                treeListInquired.Invoke(caller);   //从这里开始的调用序列就进入了UI线程,所以耗时的操作不能放在这里!!!
            } 
            else
            {
                UpdateInquiry();
            }
        }

        //callback function which is used to end the asynchronous inquiry operation and resume the 
        //enable state of related controls
        public void AsyncRefreshCallback(IAsyncResult result)
        {
            AsyncRefreshCaller inquiryDelegate = (AsyncRefreshCaller)((AsyncResult)result).AsyncDelegate;
            inquiryDelegate.EndInvoke(result);

            //enable related controls again - there may be an issue thread-safe-related - by OY
            if (bCanDemand)
            {
                dateTimePickerDate.Enabled = true;
                btnPrev.Enabled = true;
                btnNext.Enabled = true;
                btnRefresh.Enabled = true;
            }
        }

        private delegate void AsyncRefreshCaller();
        private void RefreshInquiry()
        {
            //disable related controls on GUI
            dateTimePickerDate.Enabled = false;
            btnPrev.Enabled = false;
            btnNext.Enabled = false;
            btnRefresh.Enabled = false;

            //invoke synchronous method asynchronously
            AsyncRefreshCaller inquiryDelegate = new AsyncRefreshCaller(UpdateInquiryContainer);
            AsyncCallback callback = new AsyncCallback(this.AsyncRefreshCallback);
            inquiryDelegate.BeginInvoke(callback, null);
            //inquiryDelegate.BeginInvoke(null, null);
        }


参考:MSDN(VS2005) - ms-help://MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_fxadvance/html/c6baed9f-2a25-4728-9a9a-53b7b14840cf.htm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值