用后台控件做.net多线程编程

    技术2025-05-06  14

    用后台控件做.net多线程编程

    .net框架下,很多编程工作都得以简化了,这正是MS多年来奉行的原则,那就是

    把复杂留给自己,简单的工作给你去做。在以往需要花费很多时间才能搞明白的技术,现在则变得简单明了,这里要说的是多线程,并用一项应用颇多的例子来说明,那就是界面与数据处理分开进行的技术。

    先简单说一下问题,当我们想点一下界面上的按钮,然后执行一个下载过程,然后

    再去执行其它的操作,如果简单地使用按钮的click事件,在事件里执行这个下载过程,那好,你看吧,界面好像死了一下,鼠标显示成一个漏斗形状,你就等着吧,非得等到要下载的东西下载完,click事件里的过程处理完,界面才能恢复原样,你才能进行其它操作。这个问题就是没有把耗时长的过程与界面显示分开。要想使它们两不耽误,需要把这两个过程分开,分到两个不同的线程里去,需要使用多线程技术。

    .net程序可以使用已经封装好的线程对象,相对于MFC的线程模型已经简化多了,用户可以轻松地在任何地方启动一个线程,把所要进行的数据操作地址传进去,只需要两三句代码就做到了,然而MS并不满足,对于简单的处理,这种多线程足够用了,如果要再复杂一些,如随时终止线程,线程进度报告等,也许就比较麻烦了。于是,MS又进一步把这些工作封装了起来,做了一个更简单的类,就是BackgroundWorker,后台工作者,后面简称后台。

    现在就来介绍一下后台的使用方法。首先需要把一个后台加载进界面中来,这和加一个控件没什么区别。从工具箱中找到后台,点中一拖,完事。其次,需要让这个后台做什么工作,当然需要设置了,下载东西,或者最简单的,用来做测试用的,从0数到30亿(干嘛不取1亿或者更大的数,为了看得清楚又不用等太长时间)。那么,就定义一个函数,像平时那样定义,在这个函数里从0数到30亿。然后把这个放到后台的Do_work事件里,什么是

    Do_work事件,噢,这个简单,在设计界面上选择后台控件,然后在属性页中找到它的事件列表,应该看到有一个Do_work事件。这里就是设置后台工作内容的地方。添加一个这个事件,然后在事件里写上:从0数到30亿。当然不用这么写,直接写上那个数数的函数就行了。

    这些工作做完后,还要加一个指令,就好像运动员都准备好的,就等一声发令枪响了。在设计界面中加一个按钮,然后双击这个按钮,在它的Click事件中加上:后台->RunWorkerAsync();RunWorkerAsync是后台控件的主要方法之一,作用是启动工作。这样一切都OK了,可以把程序运行起来,点击一下,看看效果。

    不知不觉地,后台在默默无闻地工作,也不知道是干完了还是正在干。如果想看出效果来,就在工作结束时,也就是数完数时,弹出一个消息框。

    这是一个最简单的程序了,也没有加取消。当然不加取消在这个程序里看不出区别

    来,不影响别的事件,界面响应自如。但如果要加强对后台的控制,就要再多做一些工作。

    如果要加上取消,回到设计界面,再添加一个按钮,用于点击后使后台取消。在取消按钮的点击事件里加上:后台->CancelAsync();这个CancelAsync也是后台的主要方法之一,用于取消工作。添加完了,再运行一下试试吧,启动后台后,再点取消...咣!出了一个异常,说得很清楚:此后台声明它不支持取消。请修改 WorkerSupportsCancellation 以声明它支持取消。那就在加载窗口时,声明它支持取消。在窗口的Load事件中写:后台->WorkerSupportsCancellation = true;原来,后台的这个属性默认是false的,不允许取消。

    这样做完了,再试一下,点启动后台,再点取消,过了一会儿,咣!弹出消息框,说它干完了,说明没有取消掉。后查了半天资料,终于弄清楚了,在数数过程中,它一直忙于数数(不停地循环),没有工夫接收消息,于是直到数完了,才接到取消的通知。

    要让它在数数过程中也能接到取消的通知才行,于是,可以在循环中加上:Application::DoEvents();这就是处理消息的意思。每数完一个数看看有没有可以处理的消息。要清楚这个是很耗时的,需要将数的数降到10万以内。运行一下看看,结果过了一会,又弹出了完工的消息框,失败。我再查资料!

    后来又发现了后台的另外一个属性:CancellationPending,资料说这个属性是标识是否请求了取消后台工作的意思。函数里要判断这个属性,及时地响应。原来也是有点麻烦的,那只好再在循环中加上一句:如果CancellationPendingtrue的话,直接返回。再试!总算成功了。。。

    那现在更进一步,想实现一个功能就是重启的功能,即点一个按钮后,先停止工作再启动工作。那么我可以在按钮事件里写:后台->CancelAsync;后台->RunWorkerAsync();这样行不行,先试一下再说。结果又弹出一个异常,说此后台当前正忙,无法同时运行多个任务。那就是说明后台没停下来呢,就又开始运行了。那好办,查资料后可以看到后台有这么一个属性IsBusy。只有当这个属性为false时才能启动后台。那当取消后台后,我就在一个循环中判断IsBusy是否为false,当为false时跳出循环,再启动后台。

    看起来可以,但是当运行起来再试的时候,发现界面死了!猛然想起循环的时候是不接收消息了,也就是说我处理不了消息,IsBusy也永远为true,当然跳不出循环了。那只好故技重施,加上DoEvents()。于是,这个任务也成功完成了。

    那么更进一步,报告进度,天!这个过程要详细描述出来太难了,大家可以自己看MSDN的资料了,而且还有百度、Google可以查,这里就不一一样述了。

    后台的其它一些属性和方法及其应用都可以MSDN、百度和Google。实在不行那只能了,呵呵。

    讲到这儿就完事了吧?我再唠叨几句,这里还要讲一个自身的经验,后台工作起来以后界面是可以响应的,但是不响应按键事件,这绝对是MS的一个bug,这是网上的一个哥们查MS的代码才查出来的。本来后台的设计只是简化一下多线程的编程,有点缺陷也是难免的,如果想实现更灵活的多线程功能的话,再看看.net的线程类这方面的资料吧。

    最新回复(0)