<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>中文 &#187; yangsh3002</title>
	<atom:link href="http://software.intel.com/zh-cn/blogs/author/yangsh3002/feed/" rel="self" type="application/rss+xml" />
	<link>http://software.intel.com/zh-cn/blogs</link>
	<description></description>
	<lastBuildDate>Mon, 28 May 2012 14:23:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>用后台控件做 .net 多线程编程</title>
		<link>http://software.intel.com/zh-cn/blogs/2011/03/24/net-2/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2011/03/24/net-2/#comments</comments>
		<pubDate>Thu, 24 Mar 2011 08:07:55 +0000</pubDate>
		<dc:creator>yangsh3002</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[并行计算]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2011/03/24/net-2/</guid>
		<description><![CDATA[  在.net框架下，很多编程工作都得以简化了，这正是MS多年来奉行的原则，那就是把复杂留给自己，简单的工作给你去做。在以往需要花费很多时间才能搞明白的技术，现在则变得简单明了，这里要说的是多线程，并用一项应用颇多的例子来说明，那就是界面与数据处理分开进行的技术。 先简单说一下问题，当我们想点一下界面上的按钮，然后执行一个下载过程，然后再去执行其它的操作，如果简单地使用按钮的click事件，在事件里执行这个下载过程，那好，你看吧，界面好像死了一下，鼠标显示成一个漏斗形状，你就等着吧，非得等到要下载的东西下载完，click事件里的过程处理完，界面才能恢复原样，你才能进行其它操作。这个问题就是没有把耗时长的过程与界面显示分开。要想使它们两不耽误，需要把这两个过程分开，分到两个不同的线程里去，需要使用多线程技术。 .net程序可以使用已经封装好的线程对象，相对于MFC的线程模型已经简化多了，用户可以轻松地在任何地方启动一个线程，把所要进行的数据操作地址传进去，只需要两三句代码就做到了，然而MS并不满足，对于简单的处理，这种多线程足够用了，如果要再复杂一些，如随时终止线程，线程进度报告等，也许就比较麻烦了。于是，MS又进一步把这些工作封装了起来，做了一个更简单的类，就是BackgroundWorker,后台工作者，后面简称后台。 现在就来介绍一下后台的使用方法。首先需要把一个后台加载进界面中来，这和加一个控件没什么区别。从工具箱中找到后台，点中一拖，完事。其次，需要让这个后台做什么工作，当然需要设置了，下载东西，或者最简单的，用来做测试用的，从0数到30亿(干嘛不取1亿或者更大的数，为了看得清楚又不用等太长时间)。那么，就定义一个函数，像平时那样定义，在这个函数里从0数到30亿。然后把这个放到后台的Do_work事件里，什么是Do_work事件，噢，这个简单，在设计界面上选择后台控件，然后在属性页中找到它的事件列表，应该看到有一个Do_work事件。这里就是设置后台工作内容的地方。添加一个这个事件，然后在事件里写上：从0数到30亿。当然不用这么写，直接写上那个数数的函数就行了。 这些工作做完后，还要加一个指令，就好像运动员都准备好的，就等一声发令枪响了。在设计界面中加一个按钮，然后双击这个按钮，在它的Click事件中加上：后台-&#62;RunWorkerAsync();RunWorkerAsync是后台控件的主要方法之一，作用是启动工作。这样一切都OK了，可以把程序运行起来，点击一下，看看效果。 不知不觉地，后台在默默无闻地工作，也不知道是干完了还是正在干。如果想看出效果来，就在工作结束时，也就是数完数时，弹出一个消息框。 这是一个最简单的程序了，也没有加取消。当然不加取消在这个程序里看不出区别来，不影响别的事件，界面响应自如。但如果要加强对后台的控制，就要再多做一些工作。 如果要加上取消，回到设计界面，再添加一个按钮，用于点击后使后台取消。在取消按钮的点击事件里加上：后台-&#62;CancelAsync();这个CancelAsync也是后台的主要方法之一，用于取消工作。添加完了，再运行一下试试吧，启动后台后，再点取消...咣！出了一个异常，说得很清楚：此后台声明它不支持取消。请修改 WorkerSupportsCancellation 以声明它支持取消。那就在加载窗口时，声明它支持取消。在窗口的Load事件中写：后台-&#62;WorkerSupportsCancellation = true;原来，后台的这个属性默认是false的，不允许取消。 这样做完了，再试一下，点启动后台，再点取消，过了一会儿，咣！弹出消息框，说它干完了，说明没有取消掉。后查了半天资料，终于弄清楚了，在数数过程中，它一直忙于数数(不停地循环)，没有工夫接收消息，于是直到数完了，才接到取消的通知。 要让它在数数过程中也能接到取消的通知才行，于是，可以在循环中加上：Application::DoEvents();这就是处理消息的意思。每数完一个数看看有没有可以处理的消息。要清楚这个是很耗时的，需要将数的数降到10万以内。运行一下看看，结果过了一会，又弹出了完工的消息框，失败。我再查资料！ 后来又发现了后台的另外一个属性:CancellationPending，资料说这个属性是标识是否请求了取消后台工作的意思。函数里要判断这个属性，及时地响应。原来也是有点麻烦的，那只好再在循环中加上一句：如果CancellationPending是true的话，直接返回。再试！总算成功了。。。 那现在更进一步，想实现一个功能就是重启的功能，即点一个按钮后，先停止工作再启动工作。那么我可以在按钮事件里写：后台-&#62;CancelAsync;后台-&#62;RunWorkerAsync();这样行不行，先试一下再说。结果又弹出一个异常，说此后台当前正忙，无法同时运行多个任务。那就是说明后台没停下来呢，就又开始运行了。那好办，查资料后可以看到后台有这么一个属性IsBusy。只有当这个属性为false时才能启动后台。那当取消后台后，我就在一个循环中判断IsBusy是否为false,当为false时跳出循环，再启动后台。 看起来可以，但是当运行起来再试的时候，发现界面死了！猛然想起循环的时候是不接收消息了，也就是说我处理不了消息，IsBusy也永远为true，当然跳不出循环了。那只好故技重施，加上DoEvents()。于是，这个任务也成功完成了。 那么更进一步，报告进度，天！这个过程要详细描述出来太难了，大家可以自己看MSDN的资料了，而且还有百度、Google可以查，这里就不一一样述了。 后台的其它一些属性和方法及其应用都可以MSDN、百度和Google。实在不行那只能CSDN了，呵呵。 讲到这儿就完事了吧？我再唠叨几句，这里还要讲一个自身的经验，后台工作起来以后界面是可以响应的，但是不响应按键事件，这绝对是MS的一个bug，这是网上的一个哥们查MS的代码才查出来的。本来后台的设计只是简化一下多线程的编程，有点缺陷也是难免的，如果想实现更灵活的多线程功能的话，再看看.net的线程类这方面的资料吧。]]></description>
			<content:encoded><![CDATA[<p> </p>
<p>在.net框架下，很多编程工作都得以简化了，这正是MS多年来奉行的原则，那就是把复杂留给自己，简单的工作给你去做。在以往需要花费很多时间才能搞明白的技术，现在则变得简单明了，这里要说的是多线程，并用一项应用颇多的例子来说明，那就是界面与数据处理分开进行的技术。</p>
<p>先简单说一下问题，当我们想点一下界面上的按钮，然后执行一个下载过程，然后再去执行其它的操作，如果简单地使用按钮的click事件，在事件里执行这个下载过程，那好，你看吧，界面好像死了一下，鼠标显示成一个漏斗形状，你就等着吧，非得等到要下载的东西下载完，click事件里的过程处理完，界面才能恢复原样，你才能进行其它操作。这个问题就是没有把耗时长的过程与界面显示分开。要想使它们两不耽误，需要把这两个过程分开，分到两个不同的线程里去，需要使用多线程技术。</p>
<p>.net程序可以使用已经封装好的线程对象，相对于MFC的线程模型已经简化多了，用户可以轻松地在任何地方启动一个线程，把所要进行的数据操作地址传进去，只需要两三句代码就做到了，然而MS并不满足，对于简单的处理，这种多线程足够用了，如果要再复杂一些，如随时终止线程，线程进度报告等，也许就比较麻烦了。于是，MS又进一步把这些工作封装了起来，做了一个更简单的类，就是BackgroundWorker,后台工作者，后面简称后台。</p>
<p>现在就来介绍一下后台的使用方法。首先需要把一个后台加载进界面中来，这和加一个控件没什么区别。从工具箱中找到后台，点中一拖，完事。其次，需要让这个后台做什么工作，当然需要设置了，下载东西，或者最简单的，用来做测试用的，从0数到30亿(干嘛不取1亿或者更大的数，为了看得清楚又不用等太长时间)。那么，就定义一个函数，像平时那样定义，在这个函数里从0数到30亿。然后把这个放到后台的Do_work事件里，什么是Do_work事件，噢，这个简单，在设计界面上选择后台控件，然后在属性页中找到它的事件列表，应该看到有一个Do_work事件。这里就是设置后台工作内容的地方。添加一个这个事件，然后在事件里写上：从0数到30亿。当然不用这么写，直接写上那个数数的函数就行了。</p>
<p>这些工作做完后，还要加一个指令，就好像运动员都准备好的，就等一声发令枪响了。在设计界面中加一个按钮，然后双击这个按钮，在它的Click事件中加上：后台-&gt;RunWorkerAsync();RunWorkerAsync是后台控件的主要方法之一，作用是启动工作。这样一切都OK了，可以把程序运行起来，点击一下，看看效果。</p>
<p>不知不觉地，后台在默默无闻地工作，也不知道是干完了还是正在干。如果想看出效果来，就在工作结束时，也就是数完数时，弹出一个消息框。</p>
<p>这是一个最简单的程序了，也没有加取消。当然不加取消在这个程序里看不出区别来，不影响别的事件，界面响应自如。但如果要加强对后台的控制，就要再多做一些工作。</p>
<p>如果要加上取消，回到设计界面，再添加一个按钮，用于点击后使后台取消。在取消按钮的点击事件里加上：后台-&gt;CancelAsync();这个CancelAsync也是后台的主要方法之一，用于取消工作。添加完了，再运行一下试试吧，启动后台后，再点取消...咣！出了一个异常，说得很清楚：此后台声明它不支持取消。请修改 WorkerSupportsCancellation 以声明它支持取消。那就在加载窗口时，声明它支持取消。在窗口的Load事件中写：后台-&gt;WorkerSupportsCancellation = true;原来，后台的这个属性默认是false的，不允许取消。</p>
<p>这样做完了，再试一下，点启动后台，再点取消，过了一会儿，咣！弹出消息框，说它干完了，说明没有取消掉。后查了半天资料，终于弄清楚了，在数数过程中，它一直忙于数数(不停地循环)，没有工夫接收消息，于是直到数完了，才接到取消的通知。</p>
<p>要让它在数数过程中也能接到取消的通知才行，于是，可以在循环中加上：Application::DoEvents();这就是处理消息的意思。每数完一个数看看有没有可以处理的消息。要清楚这个是很耗时的，需要将数的数降到10万以内。运行一下看看，结果过了一会，又弹出了完工的消息框，失败。我再查资料！</p>
<p>后来又发现了后台的另外一个属性:CancellationPending，资料说这个属性是标识是否请求了取消后台工作的意思。函数里要判断这个属性，及时地响应。原来也是有点麻烦的，那只好再在循环中加上一句：如果CancellationPending是true的话，直接返回。再试！总算成功了。。。</p>
<p>那现在更进一步，想实现一个功能就是重启的功能，即点一个按钮后，先停止工作再启动工作。那么我可以在按钮事件里写：后台-&gt;CancelAsync;后台-&gt;RunWorkerAsync();这样行不行，先试一下再说。结果又弹出一个异常，说此后台当前正忙，无法同时运行多个任务。那就是说明后台没停下来呢，就又开始运行了。那好办，查资料后可以看到后台有这么一个属性IsBusy。只有当这个属性为false时才能启动后台。那当取消后台后，我就在一个循环中判断IsBusy是否为false,当为false时跳出循环，再启动后台。</p>
<p>看起来可以，但是当运行起来再试的时候，发现界面死了！猛然想起循环的时候是不接收消息了，也就是说我处理不了消息，IsBusy也永远为true，当然跳不出循环了。那只好故技重施，加上DoEvents()。于是，这个任务也成功完成了。</p>
<p>那么更进一步，报告进度，天！这个过程要详细描述出来太难了，大家可以自己看MSDN的资料了，而且还有百度、Google可以查，这里就不一一样述了。</p>
<p>后台的其它一些属性和方法及其应用都可以MSDN、百度和Google。实在不行那只能CSDN了，呵呵。</p>
<p>讲到这儿就完事了吧？我再唠叨几句，这里还要讲一个自身的经验，后台工作起来以后界面是可以响应的，但是不响应按键事件，这绝对是MS的一个bug，这是网上的一个哥们查MS的代码才查出来的。本来后台的设计只是简化一下多线程的编程，有点缺陷也是难免的，如果想实现更灵活的多线程功能的话，再看看.net的线程类这方面的资料吧。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2011/03/24/net-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

