﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-cc-文章分类-编程相关</title><link>http://www.cppblog.com/xingmuxixi/category/3298.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 15 Jul 2008 06:27:50 GMT</lastBuildDate><pubDate>Tue, 15 Jul 2008 06:27:50 GMT</pubDate><ttl>60</ttl><item><title>C++基本类型对象化的一个方案</title><link>http://www.cppblog.com/xingmuxixi/articles/55796.html</link><dc:creator>醒目西西</dc:creator><author>醒目西西</author><pubDate>Thu, 10 Jul 2008 06:44:00 GMT</pubDate><guid>http://www.cppblog.com/xingmuxixi/articles/55796.html</guid><wfw:comment>http://www.cppblog.com/xingmuxixi/comments/55796.html</wfw:comment><comments>http://www.cppblog.com/xingmuxixi/articles/55796.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xingmuxixi/comments/commentRss/55796.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xingmuxixi/services/trackbacks/55796.html</trackback:ping><description><![CDATA[<p><strong>1.问题</strong><br>&nbsp;在很多用C++开发服务器产品时，需要将不同的数据类型存储到一个容器中(有点类似HttpSession可以保存会话期间任意类型的数据)，供其它使用程序查找。<br>&nbsp;在Java和C#中这是一个简单的问题，可以使用Object对象来实现类型无关的数据结构，并且很好的解决了内存回收等问题。<br>&nbsp;但C++中很难做到这一点，C++是一门静态类型语言，没有一个所有类型的基类。</p>
<p><br><strong>2.一般方法</strong><br>&nbsp;一般解决这个问题的办法是使用void*指针来存储数据，象下面的代码：<br>&nbsp;map&lt;string,void*&gt;<br>&nbsp;但是这样带来几个问题：<br>&nbsp;（1）因为C++在不知道类类型时无法正确的释放内存；<br>&nbsp;（2）很多使用者使用它时，释放内存的时机难于确定；</p>
<p><br><strong>3.让它正确释放内存</strong><br>&nbsp;我们可以定义一个公共的基类，让所有需要放到容器的类型继承它<br>&nbsp;class Object<br>&nbsp;{<br>&nbsp;public:<br>&nbsp;&nbsp;virtual ~Object(){cout&lt;&lt;"Object Destroy" &lt;&lt; endl;}<br>&nbsp;};<br>&nbsp;由于使用了virtual析构函数因此可以确保delete obj的时可以正常工作。因此上面的容器定义变成了这样：<br>&nbsp;map&lt;string,Object*&gt;</p>
<p><br><strong>4.让它知道何时释放内存</strong><br>&nbsp;大家都知道，这时必须使用引用计数，不过很幸运有现成的，我们使用boost::share_ptr<br>&nbsp;map&lt;string,boost::share_ptr&lt;Object*&gt; &gt;<br>&nbsp;很好两个问题都已经解决，但如何向他们中加入C++的基本类型呢？</p>
<p><br><strong>5.开发基本类型的封装类</strong><br>&nbsp;基本类型很多，如果每一个都写一个类，太累了，我们可以定义一个模板，这里的难点是基本类型之间的操作符重载，不同类型之间的运算返回的类型并不相同，这就需要写很多重载函数，在这里我们使用Loki来简化这些操作。使用Loki的TypeList来自动计算应该是什么返回值<br>&nbsp;#include"Typelist.h" //Loki头文件<br>&nbsp;template &lt;typename T&gt;<br>&nbsp;class PrimerType:public Object<br>&nbsp;{<br>&nbsp;public:<br>&nbsp;&nbsp;typedef T&nbsp;value_type;//基本类型<br>&nbsp;&nbsp;typedef PrimerType&lt;T&gt; class_type;//基本类型的对象类型<br>&nbsp;<br>&nbsp;public:<br>&nbsp;&nbsp;PrimerType()<br>&nbsp;&nbsp;&nbsp;:m_value((value_type)0)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;}<br>&nbsp;<br>&nbsp;&nbsp;template&lt;typename Other&gt;<br>&nbsp;&nbsp;&nbsp;PrimerType(const Other&amp; value)<br>&nbsp;&nbsp;&nbsp;:m_value(value)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;}<br>&nbsp;<br>&nbsp;&nbsp;~PrimerType()<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;cout&lt;&lt;"PrimerType Destroy" &lt;&lt; endl;<br>&nbsp;&nbsp;}<br>&nbsp;<br>&nbsp;&nbsp;//基本类型转换操作符重载<br>&nbsp;&nbsp;operator value_type() const<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;return m_value;<br>&nbsp;&nbsp;}<br>&nbsp;<br>&nbsp;&nbsp;//赋值操作符重载<br>&nbsp;&nbsp;const class_type&amp; operator=(value_type value)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;m_value=value;<br>&nbsp;&nbsp;&nbsp;return *this;<br>&nbsp;&nbsp;}<br>&nbsp;<br>&nbsp;&nbsp;bool operator!( ) const <br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;return !m_value;<br>&nbsp;&nbsp;}<br>&nbsp;<br>&nbsp;&nbsp;//作为类成员的算术运算符操作符重载<br>&nbsp;&nbsp;class_type&amp; operator++()<br>&nbsp;&nbsp;{// ++ 前缀<br>&nbsp;&nbsp;&nbsp;m_value+=1;<br>&nbsp;&nbsp;&nbsp;return *this;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;const class_type operator++(int)<br>&nbsp;&nbsp;{// ++ 后缀 <br>&nbsp;&nbsp;&nbsp;class_type oldValue=*this;<br>&nbsp;&nbsp;&nbsp;m_value+=1;<br>&nbsp;&nbsp;&nbsp;return oldValue;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;class_type&amp; operator--()<br>&nbsp;&nbsp;{// -- 前缀<br>&nbsp;&nbsp;&nbsp;m_value-=1;<br>&nbsp;&nbsp;&nbsp;return *this;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;const class_type operator--(int)<br>&nbsp;&nbsp;{// -- 后缀 <br>&nbsp;&nbsp;&nbsp;class_type oldValue=*this;<br>&nbsp;&nbsp;&nbsp;m_value-=1;<br>&nbsp;&nbsp;&nbsp;return oldValue;<br>&nbsp;&nbsp;}<br>&nbsp;<br>&nbsp;&nbsp;class_type&amp; operator+=(const value_type&amp; value)<br>&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;m_value+=value;<br>&nbsp;&nbsp;&nbsp;return *this;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;//。。。省略-= /= *= &amp;= |= ^= %= 等等<br>&nbsp;private:<br>&nbsp;&nbsp;value_type m_value;<br>&nbsp;&nbsp;friend istream&amp; operator&gt;&gt;&lt;T&gt; ( istream&amp; is, class_type&amp; ptvalue );<br>&nbsp;};<br>&nbsp;<br>&nbsp;//流输入函数，不用输出（通过类型操作符重载自动完成）<br>&nbsp;template&lt;typename T&gt;<br>&nbsp;istream&amp; operator&gt;&gt; ( istream&amp; is, PrimerType&lt;T&gt;&amp; ptvalue )<br>&nbsp;{<br>&nbsp;&nbsp;is &gt;&gt; ptvalue.m_value;<br>&nbsp;&nbsp;return is;<br>&nbsp;}<br>&nbsp;//基本类型重定义<br>&nbsp;typedef __int8&nbsp; int8;<br>&nbsp;typedef __int16 int16;<br>&nbsp;typedef __int32 int32;<br>&nbsp;typedef __int64 int64;<br>&nbsp;typedef unsigned __int8 uint8;<br>&nbsp;typedef unsigned __int16 uint16;<br>&nbsp;typedef unsigned __int32 uint32;<br>&nbsp;typedef unsigned __int64 uint64;<br>&nbsp;<br>&nbsp;<br>&nbsp;//基本类型的对象类型<br>&nbsp;typedef PrimerType&lt;bool&gt;&nbsp;&nbsp;&nbsp;Boolean;<br>&nbsp;typedef PrimerType&lt;int8&gt;&nbsp;&nbsp;&nbsp;Int8;<br>&nbsp;typedef PrimerType&lt;int16&gt;&nbsp;&nbsp;&nbsp;Int16;<br>&nbsp;typedef PrimerType&lt;int32&gt;&nbsp;&nbsp;&nbsp;Int32;<br>&nbsp;typedef PrimerType&lt;int64&gt;&nbsp;&nbsp;&nbsp;Int64;<br>&nbsp;typedef PrimerType&lt;uint8&gt;&nbsp;&nbsp;&nbsp;UInt8;<br>&nbsp;typedef PrimerType&lt;uint16&gt;&nbsp;&nbsp;&nbsp;UInt16;<br>&nbsp;typedef PrimerType&lt;uint32&gt;&nbsp;&nbsp;&nbsp;UInt32;<br>&nbsp;typedef PrimerType&lt;uint64&gt;&nbsp;&nbsp;&nbsp;UInt64;<br>&nbsp;typedef PrimerType&lt;float&gt;&nbsp;&nbsp;&nbsp;Float;<br>&nbsp;typedef PrimerType&lt;double&gt;&nbsp;&nbsp;&nbsp;Double;<br>&nbsp;typedef PrimerType&lt;long&gt;&nbsp;&nbsp;&nbsp;Long;<br>&nbsp;typedef PrimerType&lt;unsigned long&gt;&nbsp;ULong;<br>&nbsp;//更友好的名字<br>&nbsp;typedef Int8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Char;<br>&nbsp;typedef Int16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Short;<br>&nbsp;typedef Int32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Int;<br>&nbsp;typedef UInt8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Byte;<br>&nbsp;typedef UInt16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UShort;<br>&nbsp;typedef UInt32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UInt;<br>&nbsp;<br>&nbsp;<font color=#0000ff>//算术运算返回类型的traits，运算时以排在后面的类型返回<br>&nbsp;#define&nbsp; PRIMERTYPELIST TYPELIST_13(bool,int8,uint8,int16,uint16,int32,uint32,long,unsigned long,int64,uint64,float,double)<br>&nbsp;//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|<br>&nbsp;//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int<br>&nbsp;template &lt;typename T1, typename T2&gt;<br>&nbsp;struct ResultType_Traits<br>&nbsp;{<br>&nbsp;&nbsp;enum { lefttype_index =::Loki::TL::IndexOf&lt;PRIMERTYPELIST,T1&gt;::value};<br>&nbsp;&nbsp;enum { righttype_index =::Loki::TL::IndexOf&lt;PRIMERTYPELIST,T2&gt;::value};<br>&nbsp;&nbsp;enum { resulttype_index = (lefttype_index&gt;righttype_index)?lefttype_index:righttype_index};</p>
//在vc7.1下int32以前的类型做算术运算都返回int32类型<br>&nbsp;&nbsp;typedef typename ::Loki::TL::TypeAt&lt;PRIMERTYPELIST, (resulttype_index&lt;5)?5:resulttype_index &gt;::Result&nbsp; result_type;<br>&nbsp;};</font><br>&nbsp;<br>&nbsp;//作为全局的算术运算符操作符重载 + - * /<br>&nbsp;template&lt;typename T1,typename T2&gt;<br>&nbsp;<font color=#0000ff>typename ResultType_Traits&lt;T1,T2&gt;::result_type</font> operator +(const PrimerType&lt;T1&gt;&amp; lhs,const T2&amp; rhs)<br>&nbsp;{<br>&nbsp;&nbsp;return (T1)lhs+rhs;<br>&nbsp;}<br>&nbsp;<br>&nbsp;template&lt;typename T1,typename T2&gt;<br>&nbsp;<font color=#0000ff>typename ResultType_Traits&lt;T1,T2&gt;::result_type</font> operator +(const T1&amp; lhs,const PrimerType&lt;T2&gt;&amp; rhs)<br>&nbsp;{<br>&nbsp;&nbsp;return lhs+(T2)rhs;<br>&nbsp;}<br>&nbsp;<br>&nbsp;template&lt;typename T1,typename T2&gt;<br>&nbsp;<font color=#0000ff>typename ResultType_Traits&lt;T1,T2&gt;::result_type</font> operator +(const PrimerType&lt;T1&gt;&amp; lhs,const PrimerType&lt;T2&gt;&amp; rhs)<br>&nbsp;{<br>&nbsp;&nbsp;return (T1)lhs+(T2)rhs;<br>&nbsp;}<br>&nbsp;//。。。省略 - * /等等<br>&nbsp;<br>&nbsp;// 逻辑运算符重载<br>&nbsp;template&lt;typename T1,typename T2&gt;<br>&nbsp;bool operator ==(const PrimerType&lt;T1&gt;&amp; lhs,const T2&amp; rhs)<br>&nbsp;{<br>&nbsp;&nbsp;return (T1)lhs==rhs;<br>&nbsp;}<br>&nbsp;<br>&nbsp;template&lt;typename T1,typename T2&gt;<br>&nbsp;bool operator ==(const T1&amp; lhs,const PrimerType&lt;T2&gt;&amp; rhs)<br>&nbsp;{<br>&nbsp;&nbsp;return lhs==(T2)rhs;<br>&nbsp;}<br>&nbsp;<br>&nbsp;template&lt;typename T1,typename T2&gt;<br>&nbsp;bool operator ==(const PrimerType&lt;T1&gt;&amp; lhs,const PrimerType&lt;T2&gt;&amp; rhs)<br>&nbsp;{<br>&nbsp;&nbsp;return (T1)lhs==(T2)rhs;<br>&nbsp;}<br>&nbsp;//。。。省略 != &gt;= 等等<br>&nbsp;<br>&nbsp;<br>6.小结<br>&nbsp;使用对象来表示基本类型，由于使用了virtual的析构它是有内存浪费的，但在很多应用中它是很有用的。<br>&nbsp;同时你可以增加String/DateTime的特化支持，这样就完整了<br></font>
<img src ="http://www.cppblog.com/xingmuxixi/aggbug/55796.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xingmuxixi/" target="_blank">醒目西西</a> 2008-07-10 14:44 <a href="http://www.cppblog.com/xingmuxixi/articles/55796.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]delegate 与 多线程 </title><link>http://www.cppblog.com/xingmuxixi/articles/16694.html</link><dc:creator>醒目西西</dc:creator><author>醒目西西</author><pubDate>Thu, 21 Dec 2006 08:05:00 GMT</pubDate><guid>http://www.cppblog.com/xingmuxixi/articles/16694.html</guid><wfw:comment>http://www.cppblog.com/xingmuxixi/comments/16694.html</wfw:comment><comments>http://www.cppblog.com/xingmuxixi/articles/16694.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xingmuxixi/comments/commentRss/16694.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xingmuxixi/services/trackbacks/16694.html</trackback:ping><description><![CDATA[
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">很多时候写</span>
				<span lang="EN-US">windows</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">程序都需要结合多线程，在</span>
				<span lang="EN-US">.net</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中用如下得代码来创建并启动一个新的线程。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">public</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="COLOR: blue">void</span> ThreadProc();<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?><o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">Thread thread = <span style="COLOR: blue">new</span> Thread( <span style="COLOR: blue">new</span> ThreadStart( ThreadProc ) );<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">thread.IsBackground = <span style="COLOR: blue">true</span>;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">thread.Start();<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">但是很多时候，在新的线程中，我们需要与</span>
				<span lang="EN-US">UI</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">进行交互，在</span>
				<span lang="EN-US">.net</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中不允许我们直接这样做。可以参考</span>
				<span lang="EN-US">MSDN</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中的描述：</span>
		</p>
		<p>
				<font face="宋体">
						<span lang="EN-US" style="FONT-SIZE: 9pt">“Windows </span>
						<span style="FONT-SIZE: 9pt">窗体<span lang="EN-US">”</span>使用单线程单元<span lang="EN-US"> (STA) </span>模型，因为<span lang="EN-US">“Windows </span>窗体<span lang="EN-US">”</span>基于本机<span lang="EN-US"> Win32 </span>窗口，而<span lang="EN-US"> Win32 </span>窗口从本质上而言是单元线程。<span lang="EN-US">STA </span>模型意味着可以在任何线程上创建窗口，但窗口一旦创建后就不能切换线程，并且对它的所有函数调用都必须在其创建线程上发生。除了<span lang="EN-US"> Windows </span>窗体之外，<span lang="EN-US">.NET Framework </span>中的类使用自由线程模型。<span lang="EN-US"><o:p></o:p></span></span>
				</font>
		</p>
		<p>
				<font face="宋体">
						<span lang="EN-US" style="FONT-SIZE: 9pt">STA </span>
						<span style="FONT-SIZE: 9pt">模型要求需从控件的非创建线程调用的控件上的任何方法必须被封送到（在其上执行）该控件的创建线程。基类<span lang="EN-US"> Control </span>为此目的提供了若干方法（<span lang="EN-US">Invoke</span>、<span lang="EN-US">BeginInvoke </span>和<span lang="EN-US"> EndInvoke</span>）。<b><span lang="EN-US">Invoke</span></b><span lang="EN-US"></span>生成同步方法调用；<b><span lang="EN-US">BeginInvoke</span></b><span lang="EN-US"></span>生成异步方法调用。<span lang="EN-US"><o:p></o:p></span></span>
				</font>
		</p>
		<p>
				<font face="宋体">
						<span lang="EN-US" style="FONT-SIZE: 9pt">Windows </span>
						<span style="FONT-SIZE: 9pt">窗体中的控件被绑定到特定的线程，不具备线程安全性。因此，如果从另一个线程调用控件的方法，那么必须使用控件的一个<span lang="EN-US"> Invoke </span>方法来将调用封送到适当的线程。<span lang="EN-US"><o:p></o:p></span></span>
				</font>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">正如所看到的，我们必须调用</span>
				<span lang="EN-US">Invoke</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法，而</span>
				<span lang="EN-US">BeginInvoke</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可以认为是</span>
				<span lang="EN-US">Invoke</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的异步版本。调用方法如下：</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">public</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="COLOR: blue">delegate</span>
						<span style="COLOR: blue">void</span> OutDelegate(<span style="COLOR: blue">string</span> text);<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">public</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="COLOR: blue">void</span> OutText(<span style="COLOR: blue">string</span> text)<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>txt.AppendText(text);<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>txt.AppendText( "\t\n" );<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">OutDelegate outdelegate = <span style="COLOR: blue">new</span> OutDelegate( OutText );<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">this</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">.BeginInvoke(outdelegate, <span style="COLOR: blue">new</span><span style="COLOR: blue">object</span>[]{text});<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果我们需要在另外一个线程里面对</span>
				<span lang="EN-US">UI</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">进行操作，我们需要一个类似</span>
				<span lang="EN-US">OutText</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的函数，还需要一个该函数的委托</span>
				<span lang="EN-US">delegate</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，当然，这里展示的是自定义的，</span>
				<span lang="EN-US">.net</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中还有很多其他类型的委托，可以直接使用，不需要而外声明。例如：</span>
				<span lang="EN-US">MethodInvoker</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</span>
				<span lang="EN-US">EventHandler</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，这两种类型委托的函数外观是固定的，</span>
				<span lang="EN-US">MethodInvoker</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</span>
				<span lang="EN-US">void Function()</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类型的委托，而</span>
				<span lang="EN-US">EventHandler</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是</span>
				<span lang="EN-US">void Function(object, EventArgs)</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">类型的委托，第一个不支持参数，第二中的参数类型和数量都是固定的，这两种委托可以很方便的调用，但是缺乏灵活性。请注意</span>
				<span lang="EN-US">BeginInvoke</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">前面的对象是</span>
				<span lang="EN-US">this</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，也就是主线程。现在再介绍</span>
				<span lang="EN-US">Control.InvokeRequired</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，</span>
				<span lang="EN-US">Control</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是所有控件的基类，对于这个属性</span>
				<span lang="EN-US">MSDN</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的描述是：</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">获取一个值，该值指示调用方在对控件进行方法调用时是否必须调用</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt"> Invoke </span>
				<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法，因为调用方位于创建控件所在的线程以外的线程中。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">该属性可用于确定是否必须调用</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt"> Invoke </span>
				<span style="FONT-SIZE: 9pt; FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">方法，当不知道什么线程拥有控件时这很有用。</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">也就是说通过判断</span>
				<span lang="EN-US">InvokeRequired</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可以知道是否需要用委托来调用当前控件的一些方法，如此可以把</span>
				<span lang="EN-US">OutText</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数修改一下：</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">public</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="COLOR: blue">delegate</span>
						<span style="COLOR: blue">void</span> OutDelegate(<span style="COLOR: blue">string</span> text);<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">public</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="COLOR: blue">void</span> OutText(<span style="COLOR: blue">string</span> text)<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>
						<span style="COLOR: blue">if</span>( txt.InvokeRequired )<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">         </span>OutDelegate outdelegate = <span style="COLOR: blue">new</span> OutDelegate( OutText );<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">         </span>
						<span style="COLOR: blue">this</span>.BeginInvoke(outdelegate, <span style="COLOR: blue">new</span><span style="COLOR: blue">object</span>[]{text});<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">         </span>
						<span style="COLOR: blue">return</span>;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>txt.AppendText(text);<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>txt.AppendText( "\t\n" );<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">注意，这里的函数没有返回，如果有返回，需要调用</span>
				<span lang="EN-US">Invoke</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或者</span>
				<span lang="EN-US">EndInvoke</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">来获得返回的结果，不要因为包装而丢失了返回值。如果调用没有完成，</span>
				<span lang="EN-US">Invoke</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">和</span>
				<span lang="EN-US">EndInvoke</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">都将会引起阻塞。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">现在如果我有一个线程函数如下：</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">public</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="COLOR: blue">void</span> ThreadProc()<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>
						<span style="COLOR: blue">for</span>(<span style="COLOR: blue">int</span> i = 0; i &lt; 5; i++)<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">         </span>OutText( i.ToString() );<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">         </span>Thread.Sleep(1000);<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果循环的次数很大，或者漏了</span>
				<span lang="EN-US">Thread.Sleep(1000);</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，那么你的</span>
				<span lang="EN-US">UI</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">肯定会停止响应，想知道原因吗？看看</span>
				<span lang="EN-US">BeginInvoke</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">前面的对象，没错，就是</span>
				<span lang="EN-US">this</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，也就是主线程，当你的主线程不停的调用</span>
				<span lang="EN-US">OutText</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">的时候，</span>
				<span lang="EN-US">UI</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">当然会停止响应。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span lang="EN-US">
						<o:p> </o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">与以前</span>
				<span lang="EN-US">VC</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">中创建一个新的线程需要调用</span>
				<b>
						<span lang="EN-US">AfxBeginThread</span>
				</b>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-weight: bold">函数，该函数中第一个参数就是线程函数的地址，而第二个参数是一个类型为</span>
				<span lang="EN-US" style="mso-bidi-font-weight: bold">LPVOID</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-weight: bold">的指针类型，这个参数将传递给线程函数。现在我们没有办法再使用这种方法来传递参数了。我们需要将传递给线程的参数和线程函数包装成一个单独的类，然后在这个类的构造函数中初始化该线程所需的参数，然后再将该实例的线程函数传递给</span>
				<span lang="EN-US" style="mso-bidi-font-weight: bold">Thread</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-weight: bold">类的构造函数。代码大致如下：</span>
				<span lang="EN-US" style="mso-bidi-font-weight: bold">
						<o:p>
						</o:p>
				</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">public</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="COLOR: blue">class</span> ProcClass<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>
						<span style="COLOR: blue">private</span>
						<span style="COLOR: blue">string</span> procParameter = "";<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>
						<span style="COLOR: blue">public</span> ProcClass(<span style="COLOR: blue">string</span> parameter)<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">         </span>procParameter = parameter;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>
						<span style="COLOR: blue">public</span>
						<span style="COLOR: blue">void</span> ThreadProc()<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">ProcClass threadProc = <span style="COLOR: blue">new</span> ProcClass("use thread class");<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">Thread thread = <span style="COLOR: blue">new</span> Thread( <span style="COLOR: blue">new</span> ThreadStart( threadProc.ThreadProc ) );<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">thread.IsBackground = <span style="COLOR: blue">true</span>;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">thread.Start();<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">就是这样，需要建立一个中间类来传递线程所需的参数。</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">那么如果我的线程又需要参数，又需要和</span>
				<span lang="EN-US">UI</span>
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">进行交互的时候该怎么办呢？可以修改一下代码：</span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">public</span>
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="COLOR: blue">class</span> ProcClass<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>
						<span style="COLOR: blue">private</span>
						<span style="COLOR: blue">string</span> procParameter = "";<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>
						<span style="COLOR: blue">private</span> Form1.OutDelegate delg = <span style="COLOR: blue">null</span>;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>
						<span style="COLOR: blue">public</span> ProcClass(<span style="COLOR: blue">string</span> parameter, Form1.OutDelegate delg)<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">         </span>procParameter = parameter;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">         </span>
						<span style="COLOR: blue">this</span>.delg = delg;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>
						<span style="COLOR: blue">public</span>
						<span style="COLOR: blue">void</span> ThreadProc()<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>{<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 2">         </span>delg.BeginInvoke("use ProcClass.ThreadProc()", <span style="COLOR: blue">null</span>, <span style="COLOR: blue">null</span>);<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">
						<span style="mso-tab-count: 1">     </span>}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">}<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">ProcClass threadProc = <span style="COLOR: blue">new</span> ProcClass("use thread class", <span style="COLOR: blue">new</span> OutDelegate(OutText));<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">Thread thread = <span style="COLOR: blue">new</span> Thread( <span style="COLOR: blue">new</span> ThreadStart( threadProc.ThreadProc ) );<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">thread.IsBackground = <span style="COLOR: blue">true</span>;<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align="left">
				<span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-hansi-font-family: 'Times New Roman'; mso-font-kerning: 0pt">thread.Start();<o:p></o:p></span>
		</p>
		<p class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
				<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">这里只是我的一些理解，如果有什么错误或者不当的地方，欢迎指出。</span>
		</p>
<img src ="http://www.cppblog.com/xingmuxixi/aggbug/16694.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xingmuxixi/" target="_blank">醒目西西</a> 2006-12-21 16:05 <a href="http://www.cppblog.com/xingmuxixi/articles/16694.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>去腾讯时遇到的一个面试题</title><link>http://www.cppblog.com/xingmuxixi/articles/16551.html</link><dc:creator>醒目西西</dc:creator><author>醒目西西</author><pubDate>Sun, 17 Dec 2006 07:33:00 GMT</pubDate><guid>http://www.cppblog.com/xingmuxixi/articles/16551.html</guid><wfw:comment>http://www.cppblog.com/xingmuxixi/comments/16551.html</wfw:comment><comments>http://www.cppblog.com/xingmuxixi/articles/16551.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/xingmuxixi/comments/commentRss/16551.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xingmuxixi/services/trackbacks/16551.html</trackback:ping><description><![CDATA[/**<br /> * 分离字符串<br /> * 这个类的功能，是把指定的字符串，以‘|’为界，把字符串分离<br /> * 去腾讯面试手机开发的时候遇到的面试题，当时由于对java语言细节不熟悉，<br /> * 没做出来，所以一直耿耿于怀<br /> * 由于使用了String和List，使得用java实现变得很简单<br /> * 用c实现才是王道<br /> */<img src ="http://www.cppblog.com/xingmuxixi/aggbug/16551.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xingmuxixi/" target="_blank">醒目西西</a> 2006-12-17 15:33 <a href="http://www.cppblog.com/xingmuxixi/articles/16551.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>腾讯最新面试题,算法高手请进</title><link>http://www.cppblog.com/xingmuxixi/articles/16545.html</link><dc:creator>醒目西西</dc:creator><author>醒目西西</author><pubDate>Sun, 17 Dec 2006 07:31:00 GMT</pubDate><guid>http://www.cppblog.com/xingmuxixi/articles/16545.html</guid><wfw:comment>http://www.cppblog.com/xingmuxixi/comments/16545.html</wfw:comment><comments>http://www.cppblog.com/xingmuxixi/articles/16545.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/xingmuxixi/comments/commentRss/16545.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xingmuxixi/services/trackbacks/16545.html</trackback:ping><description><![CDATA[
		<span style="FONT-SIZE: 13px">1,两个整数集合A,B,求其交集,要求写出代码;<br />2,求一个论坛的在线人数,假设有一个论坛,其注册ID有两忆个,每个ID从登陆到退出会向一个日志文件中记下登陆时间和退出时间,要求写一个算法统计一天中论坛的用户在线分布,取样粒度为秒.</span>
<img src ="http://www.cppblog.com/xingmuxixi/aggbug/16545.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xingmuxixi/" target="_blank">醒目西西</a> 2006-12-17 15:31 <a href="http://www.cppblog.com/xingmuxixi/articles/16545.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一道腾讯的面试题 </title><link>http://www.cppblog.com/xingmuxixi/articles/16542.html</link><dc:creator>醒目西西</dc:creator><author>醒目西西</author><pubDate>Sun, 17 Dec 2006 07:30:00 GMT</pubDate><guid>http://www.cppblog.com/xingmuxixi/articles/16542.html</guid><wfw:comment>http://www.cppblog.com/xingmuxixi/comments/16542.html</wfw:comment><comments>http://www.cppblog.com/xingmuxixi/articles/16542.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/xingmuxixi/comments/commentRss/16542.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xingmuxixi/services/trackbacks/16542.html</trackback:ping><description><![CDATA[class a<br />{<br />word m_a1;<br />word m_a2;<br />a(){m_a1=1;m_a2=2;}<br />void fun(){printf("%d,%d",m_a1,m_a2);}<br />}<br />class b<br />{<br />dword m_a3;<br />b(){m_a3=3;}<br />void fun(){printf("%d",m_a3);}<br />}<br />main()<br />{<br />a a;<br />b *pb;<br />pb=b*(&amp;a);<br />pb-&gt;fun();<br />}<br />输出是什么？<br /><img src ="http://www.cppblog.com/xingmuxixi/aggbug/16542.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xingmuxixi/" target="_blank">醒目西西</a> 2006-12-17 15:30 <a href="http://www.cppblog.com/xingmuxixi/articles/16542.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c#多线程教学(4):线程池和异步编程</title><link>http://www.cppblog.com/xingmuxixi/articles/16096.html</link><dc:creator>醒目西西</dc:creator><author>醒目西西</author><pubDate>Thu, 07 Dec 2006 07:05:00 GMT</pubDate><guid>http://www.cppblog.com/xingmuxixi/articles/16096.html</guid><wfw:comment>http://www.cppblog.com/xingmuxixi/comments/16096.html</wfw:comment><comments>http://www.cppblog.com/xingmuxixi/articles/16096.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xingmuxixi/comments/commentRss/16096.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xingmuxixi/services/trackbacks/16096.html</trackback:ping><description><![CDATA[
		<p>如果你仔细阅读了我前面的三篇文章,我相信你对用.NET Framework提供的System.Threading.Thread类和一些线程同步的类基本的线程知识和多线程编程知识很了解。我们将在这里进一步讨论一些.NET类,以及他们在多线程编程中扮演的角色和怎么编程。它们是:<br /><br />　　<strong>System.Threading.ThreadPool 类</strong><br /><br />　　<strong>System.Threading.Timer 类<br /></strong><br />　　如果线程的数目并不是很多,而且你想控制每个线程的细节诸如线程的优先级等,使用Thread是比较合适的;但是如果有大量的线程,考虑使用线程池应该更好一些,它提供了高效的线程管理机制来处理多任务。 对于定期的执行任务Timer类是合适的;使用代表是异步方法调用的首选。<br /><br /><strong>System.Threading.ThreadPool Class</strong><br /><br />　　当你创建应用程序时,你应该认识到大部分时间你的线程在空闲的等待某些事件的发生(诸如按下一个键或侦听套节子的请求)。毫无疑问的,你也会认为这是绝对的浪费资源。<br /><br />　　如果这里有很多的任务需要完成,每个任务需要一个线程,你应该考虑使用线程池来更有效的管理你的资源并且从中受益。线程池是执行的多个线程集合,它允许你添加以线程自动创建和开始的任务到队列里面去。使用线程池使得你的系统可以优化线程在CPU使用时的时间碎片。但是要记住在任何特定的时间点,每一个进程和每个线程池只有一个一个正在运行的线程。这个类使得你的线程组成的池可以被系统管理,而使你的主要精力集中在工作流的逻辑而不是线程的管理。<br /><br />　　当第一次实例化ThreadPool类时线程池将被创建。它有一个默认的上限,即每处理器最多可以有25个,但是这个上限是可以改变的。这样使得处理器不会闲置下来。如果其中一个线程等待某个事件的发生,线程池将初始化另外一个线程并投入处理器工作,线程池就是这样不停的创建工作的线程和分配任务给那些没有工作的在队列里的线程。唯一的限制是工作线程的数目不能超过最大允许的数目。每个线程将运行在默认的优先级和使用默认的属于多线程空间的堆栈大小空间。一旦一项工作任务被加入队列,你是不能取消的。<br /><br />　　请求线程池处理一个任务或者工作项可以调用QueueUserWorkItem方法。这个方法带一个WaitCallback代表类型的参数,这个参数包装了你药完成的任务。运行时自动为每一个的任务创建线程并且在任务释放时释放线程。<br /><br />　　下面的代码说明了如何创建线程池和怎样添加任务:<br /></p>
		<p class="code">public void afunction(object o) <br /><br />{ <br /><br /><font color="#009900">// do what ever the function is supposed to do.</font><br /><br />} <br /><br /><font color="#009900">//thread entry code</font><br /><br />{ <br /><br /><font color="#009900">// create an instance of WaitCallback</font><br /><br />WaitCallback myCallback = new WaitCallback (afunction); <br /><br /><font color="#009900">//add this to the thread pool / queue a task</font><br /><br />ThreadPool.QueueUserWorkItem (myCallback); <br /><br />}</p>
		<p>
				<br />　　你也可以通过调用ThreadPool.RegisterWaitForSingleObject方法来传递一个System.Threading.WaitHandle,当被通知或者时间超过了调用被System.Threading.WaitOrTimerCallback包装的方法。</p>
		<p>　　线程池和基于事件的编程模式使得线程池对注册的WaitHandles的监控和对合适的WaitOrTimerCallback代表方法的调用十分简单(当WaitHandle被释放时)。这些做法其实很简单。这里有一个线程不断的观测在线程池队列等待操作的状态。一旦等待操作完成,一个线程将被执行与其对应的任务。因此,这个方法随着出发触发事件的发生而增加一个线程。<br /><br />　　让我们看看怎么随事件添加一个线程到线程池,其实很简单。我们只需要创建一个ManualResetEvent类的事件和一个WaitOrTimerCallback的代表,然后我们需要一个携带代表状态的对象,同时我们也要决定休息间隔和执行方式。我们将上面的都添加到线程池,并且激发一个事件:<br /></p>
		<p class="code">public void afunction(object o) <br /><br />{ <br /><br /><font color="#009900">// do what ever the function is supposed to do.</font><br /><br />} <br /><br /><br /><font color="#009900">//object that will carry the status information</font></p>
		<p class="code">public class anObject <br /><br />{ <br /><br />} <br /><br /><font color="#009900">//thread entry code</font><br /><br />{ <br /><br /><font color="#009900">//create an event object</font><br /><br />ManualResetEvent aevent = new ManualResetEvent (false); <br /><br /><br /><font color="#009900">// create an instance of WaitOrTimerCallback</font><br /><br />WaitOrTimerCallback thread_method = new WaitOrTimerCallback (afunction); <br /><br /><br /><font color="#009900">// create an instance of anObject</font><br /><br />anObject myobj = new anObject(); <br /><br /><br /><font color="#009900">// decide how thread will perform</font><br /><br />int timeout_interval = 100; <font color="#009900">// timeout in milli-seconds.</font><br /><br />bool onetime_exec = true; <br /><br /><br /><font color="#009900">//add all this to the thread pool.</font><br /><br />ThreadPool. RegisterWaitForSingleObject (aevent, thread_method, myobj, timeout_interval, onetime_exec); <br /><br /><br /><font color="#009900">// raise the event</font><br /><br />aevent.Set(); <br /><br />}</p>
		<p>
				<br />　　在QueueUserWorkItem和RegisterWaitForSingleObject方法中,线程池创建了一个后台的线程来回调。当线程池开始执行一个任务,两个方法都将调用者的堆栈合并到线程池的线程堆栈中。如果需要安全检查将耗费更多的时间和增加系统的负担,因此可以通过使用它们对应的不安全的方法来避免安全检查。就是ThreadPool.UnsafeRegisterWaitForSingleObject 和ThreadPool.UnsafeQueueUserWorkItem。<br /><br />　　你也可以对与等待操作无关的任务排队。 Timer-queue timers and registered wait operations也使用线程池。它们的返回方法也被放入线程池排队。<br /><br />　　线程池是非常有用的,被广泛的用于。NET平台上的套节子编程,等待操作注册,进程计时器和异步的I/O。对于小而短的任务,线程池提供的机制也是十分便利处于多线程的。线程池对于完成许多独立的任务而且不需要逐个的设置线程属性是十分便利的。但是,你也应该很清楚,有很多的情况是可以用其他的方法来替代线程池的。比如说你的计划任务或给每个线程特定的属性,或者你需要将线程放入单个线程的空间(而线程池是将所有的线程放入一个多线程空间),抑或是一个特定的任务是很冗长的,这些情况你最好考虑清楚,安全的办法比用线程池应该是你的选择。<br /><br /><br /><strong>System.Threading.Timer Class</strong><br /><br />　　Timer类对于周期性的在分离的线程执行任务是非常有效的,它不能被继承。<br /><br />　　这个类尤其用来开发控制台应用程序,因为System.Windows.Forms.Time是不可用的。比如同来备份文件和检查数据库的一致性。</p>
		<p>　　当创建Timer对象时,你药估计在第一个代理调用之前等待的时间和后来的每次成功调用之间的时间。一个定时调用发生在方法的应得时间过去,并且在后来周期性的调用这个方法。你可以适应Timer的Change方法来改变这些设置的值或者使Timer失效。当定时器Timer不再使用时,你应该调用Dispose方法来释放其资源。<br /><br />　　TimerCallback代表负责指定与Timer对象相关联的方法(就是要周期执行的任务)和状态。它在方法应得的时间过去之后调用一次并且周期性的调用这个方法直到调用了Dispose方法释放了Timer的所有资源。系统自动分配分离的线程。<br /><br />　　让我们来看一段代码看看事如何创建Timer对象和使用它的。我们首先要创建一个TimerCallback代理,在后面的方法中要使用到的。如果需要,下一步我们要创建一个状态对象,它拥有与被代理调用的方法相关联的特定信息。为了使这些简单一些,我们传递一个空参数。我们将实例化一个Timer对象,然后再使用Change方法改变Timer的设置,最后调用Dispose方法释放资源。<br /></p>
		<p class="code">
				<font color="#009900">// class that will be called by the Timer</font>
				<br />
				<br />public class WorkonTimerReq <br /><br />{ <br /><br />public void aTimerCallMethod() <br /><br />{ <br /><br /><font color="#009900">// does some work</font><br /><br />} <br /><br />} <br /><br /><br /><font color="#009900">//timer creation block</font><br /><br />{ <br /><br /><font color="#009900">//instantiating the class that gets called by the Timer.</font><br /><br />WorkonTimerReq anObj = new WorkonTimerReq () ; <br /><br /><br /><font color="#009900">// callback delegate</font><br /><br />TimerCallback tcallback = new TimerCallback(anObj. aTimerCallMethod) ; <br /><br /><br /><font color="#009900">// define the dueTime and period</font><br /><br />long dTime = 20 ; <font color="#009900">// wait before the first tick (in ms)</font><br /><br />long pTime = 150 ; <font color="#009900">// timer during subsequent invocations (in ms)</font><br /><br /><br /><font color="#009900">// instantiate the Timer object</font><br /><br />Timer atimer = new Timer(tcallback, null, dTime, pTime) ; <br /><br /><br /><font color="#009900">// do some thing with the timer object</font><br /><br />... <br /><br /><font color="#009900">//change the dueTime and period of the Timer</font><br /><br />dTime=100; <br /><br />pTime=300; <br /><br />atimer.Change(dTime, pTime) ; <br /><br /><font color="#009900">// do some thing</font><br /><br />... <br /><br />atimer.Dispose() ; <br /><br />... <br /><br />}</p>
		<p>
				<br />
				<br />
				<strong>异步编程</strong>
				<br />
				<br />　　这部分内容如果要讲清楚本来就是很大的一部分,在这里,我不打算详细讨论这个东西,我们只是需要直到它是什么,因为多线程编程如果忽律异步的多线程编程显然是不应该的。异步的多线程编程是你的程序可能会用到的另外一种多线程编程方法。<br /><br />　　在前面的文章我们花了很大的篇幅来介绍线程的同步和怎么实现线程的同步,但是它有一个固有的致命的缺点,你或许注意到了这一点。那就是每个线程必须作同步调用,也就是等到其他的功能完成,否则就阻塞。当然,某些情况下,对于那些逻辑上相互依赖的任务来说是足够的。异步编程允许更加复杂的灵活性。一个线程可以作异步调用,不需要等待其他的东西。你可以使用这些线程作任何的任务,线程负责获取结果推进运行。这给予了那些需要管理数目巨大的请求而且负担不起请求等待代价的企业级的系统更好的可伸缩性。<br /><br />　　.NET平台提供了一致的异步编程机制用于ASP.NET,I/O,Web Services,Networking,Message等。<br /><br /><br /><strong>后记</strong><br /><br />　　由于学习的时候很难找到中文这方面的资料，因此我就只好学习英文的资料，由于水平不高，翻译的时候可能难免曲解原文的意思，希望大家能够指出，同时希望这些东西能够给大家在学习这方面知识给予一定的参考和帮助，那怕是一点点，就很欣慰了。</p>
<img src ="http://www.cppblog.com/xingmuxixi/aggbug/16096.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xingmuxixi/" target="_blank">醒目西西</a> 2006-12-07 15:05 <a href="http://www.cppblog.com/xingmuxixi/articles/16096.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>c#.net多线程编程教学(2):Thread类 </title><link>http://www.cppblog.com/xingmuxixi/articles/16094.html</link><dc:creator>醒目西西</dc:creator><author>醒目西西</author><pubDate>Thu, 07 Dec 2006 07:03:00 GMT</pubDate><guid>http://www.cppblog.com/xingmuxixi/articles/16094.html</guid><wfw:comment>http://www.cppblog.com/xingmuxixi/comments/16094.html</wfw:comment><comments>http://www.cppblog.com/xingmuxixi/articles/16094.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xingmuxixi/comments/commentRss/16094.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xingmuxixi/services/trackbacks/16094.html</trackback:ping><description><![CDATA[
		<p>这章将向大家介绍.NET中的线程API,怎么样用C#创建线程,启动和停止线程,设置优先级和状态.<br /><br />　　在.NET中编写的程序将被自动的分配一个线程.让我们来看看用C#编程语言创建线程并且继续<nobr><a class="iAs" oncontextmenu="return false;" onmousemove="kwM(2);" onmouseover="kwE(event,2);" style="CURSOR: hand; COLOR: #0000ff; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline" onclick="window.open('http://114.vnet.cn/search_web.html?id=148&amp;kw=学习','_blank');" onmouseout="kwL(event);" target="_blank">学习</a></nobr>线程的知识。我们都知道.NET的运行时环境的主线程由Main ()方法来启动应用程序，而且.NET的编译语言有自动的垃圾收集功能,这个垃圾收集发生在另外一个线程里面,所有的这些都是后台发生的,让我们无法感觉到发生了什么事情.在这里默认的是只有一个线程来完成所有的程序任务，但是正如我们在第一篇文章讨论过的一样，有可能我们根据需要自己添加更多的线程让程序更好的协调<nobr><a class="iAs" oncontextmenu="return false;" onmousemove="kwM(4);" onmouseover="kwE(event,4);" style="CURSOR: hand; COLOR: #0000ff; BACKGROUND-COLOR: transparent; TEXT-DECORATION: underline" onclick="window.open('http://114.vnet.cn/search_web.html?id=148&amp;kw=工作','_blank');" onmouseout="kwL(event);" target="_blank">工作</a></nobr>。比如说我们的例子中，一个有用户输入的同时需要绘制图形或者完成大量的运算的程序，我们必须得增加一个线程，让用户的输入能够得到及时的响应，因为输入对时间和响应的要求是紧迫的，而另外一个线程负责图形绘制或者大量的运算。<br /><br />　　.NET 基础类库的System.Threading命名空间提供了大量的类和接口支持多线程。这个命名空间有很多的类，我们将在这里着重讨论Thread这个类。<br /><br />　　System.Threading.Thread类是创建并控制线程，设置其优先级并获取其状态最为常用的类。他有很多的方法，在这里我们将就比较常用和重要的方法做一下介绍：<br /><br />　　Thread.Start（）：启动线程的执行；<br /><br />　　Thread.Suspend（）：挂起线程，或者如果线程已挂起，则不起作用；<br /><br />　　Thread.Resume（）：继续已挂起的线程；<br /><br />　　Thread.Interrupt（）：中止处于 Wait或者Sleep或者Join 线程状态的线程；<br /><br />　　Thread.Join（）：阻塞调用线程，直到某个线程终止时为止<br /><br />　　Thread.Sleep（）：将当前线程阻塞指定的毫秒数；<br /><br />　　Thread.Abort（）：以开始终止此线程的过程。如果线程已经在终止，则不能通过Thread.Start（）来启动线程。<br /><br />　　通过调用Thread.Sleep，Thread.Suspend或者Thread.Join可以暂停/阻塞线程。调用Sleep()和Suspend()方法意味着线程将不再得到CPU时间。这两种暂停线程的方法是有区别的，Sleep()使得线程立即停止执行，但是在调用Suspend()方法之前，公共语言运行时必须到达一个安全点。一个线程不能对另外一个线程调用Sleep()方法，但是可以调用Suspend()方法使得另外一个线程暂停执行。对已经挂起的线程调用Thread.Resume（）方法会使其继续执行。不管使用多少次Suspend()方法来阻塞一个线程，只需一次调用Resume()方法就可以使得线程继续执行。已经终止的和还没有开始执行的线程都不能使用挂起。Thread.Sleep（int x）使线程阻塞x毫秒。只有当该线程是被其他的线程通过调用Thread.Interrupt（）或者Thread.Abort（）方法，才能被唤醒。 </p>
		<p>　　如果对处于阻塞状态的线程调用Thread.Interrupt（）方法将使线程状态改变，但是会抛出ThreadInterupptedException异常，你可以捕获这个异常并且做出处理，也可以忽略这个异常而让运行时终止线程。在一定的等待时间之内，Thread.Interrupt（）和Thread.Abort（）都可以立即唤醒一个线程。<br /><br />　　下面我们将说明如何从一个线程中止另外一个线程。在这种情况下，我们可以通过使用Thread.Abort（）方法来永久销毁一个线程，而且将抛出ThreadAbortException异常。使终结的线程可以捕获到异常但是很难控制恢复，仅有的办法是调用Thread.ResetAbort（）来取消刚才的调用，而且只有当这个异常是由于被调用线程引起的异常。因此，A线程可以正确的使用Thread.Abort（）方法作用于B线程，但是B线程却不能调用Thread.ResetAbort（）来取消Thread.Abort（）操作。</p>
		<p>　　Thread.Abort（）方法使得系统悄悄的销毁了线程而且不通知用户。一旦实施Thread.Abort（）操作，该线程不能被重新启动。调用了这个方法并不是意味着线程立即销毁，因此为了确定线程是否被销毁，我们可以调用Thread.Join（）来确定其销毁，Thread.Join（）是一个阻塞调用，直到线程的确是终止了才返回。但是有可能一个线程调用Thread.Interrupt（）方法来中止另外一个线程，而这个线程正在等待Thread.Join（）调用的返回。</p>
		<p>　　尽可能的不要用Suspend()方法来挂起阻塞线程，因为这样很容易造成死锁。假设你挂起了一个线程，而这个线程的资源是其他线程所需要的，会发生什么后果。因此，我们尽可能的给重要性不同的线程以不同的优先级，用Thread.Priority（）方法来代替使用Thread.Suspend（）方法。<br /><br />　　Thread类有很多的属性，这些重要的属性是我们多线程编程必须得掌握的。<br /><br />　　Thread.IsAlive属性：获取一个值，该值指示当前线程的执行状态。如果此线程已启动并且尚未正常终止或中止，则为 true；否则为 false。<br /><br />　　Thread.Name 属性：获取或设置线程的名称。<br /><br />　　Thread.Priority 属性：获取或设置一个值，该值指示线程的调度优先级。<br />　　Thread.ThreadState 属性：获取一个值，该值包含当前线程的状态。<br />　　在下面的例子中，我们将看看怎么设置这些属性，在随后的例子中我们将详细的讨论这些属性。<br />　　创建一个线程，首先得实例化一个Thread类，在类得构造函数中调用ThreadStart委派。这个委派包含了线程从哪里开始执行。当线程启动后，Start()方法启动一个新的线程。下面是例子程序。<br /></p>
		<p>
		</p>
		<p class="code">using System;<br />using System.Threading ;<br />namespace LearnThreads<br />{ <br />class Thread_App<br />{<br />public static void First_Thread()<br />{<br />　Console.WriteLine("First thread created");<br />　Thread current_thread = Thread.CurrentThread;<br />　string thread_details = "Thread Name: " + current_thread.Name + "\r\nThread State: " + current_thread.ThreadState.ToString()+"\r\n Thread Priority level:"+current_thread.Priority.ToString();<br />　Console.WriteLine("The details of the thread are :"+ thread_details);<br />　Console.WriteLine ("first thread terminated");<br />}<br /><br />public static void Main()<br />{<br />　ThreadStart thr_start_func = new ThreadStart (First_Thread);<br />　Console.WriteLine ("Creating the first thread ");<br />　Thread fThread = new Thread (thr_start_func);<br />　fThread.Name = "first_thread";<br />　fThread.Start (); //starting the thread<br />}<br />}<br />}</p>
		<p>
				<br />　　在这个例子中，创建了一个fThread的线程对象，这个线程负责执行First_Thread()方法里面的任务。当Thread的Start() 方法被调用时包含First_Thread()的地址ThreadStart的代理将被执行。<br /><br /><strong>Thread状态</strong><br />　　System.Threading.Thread.ThreadState属性定义了执行时线程的状态。线程从创建到线程终止，它一定处于其中某一个状态。当线程被创建时，它处在Unstarted状态，Thread类的Start() 方法将使线程状态变为Running状态，线程将一直处于这样的状态，除非我们调用了相应的方法使其挂起、阻塞、销毁或者自然终止。如果线程被挂起，它将处于Suspended状态，除非我们调用resume（）方法使其重新执行，这时候线程将重新变为Running状态。一旦线程被销毁或者终止，线程处于Stopped状态。处于这个状态的线程将不复存在，正如线程开始启动，线程将不可能回到Unstarted状态。线程还有一个Background状态，它表明线程运行在前台还是后台。在一个确定的时间，线程可能处于多个状态。据例子来说，一个线程被调用了Sleep而处于阻塞，而接着另外一个线程调用Abort方法于这个阻塞的线程，这时候线程将同时处于WaitSleepJoin和AbortRequested状态。一旦线程响应转为Sle阻塞或者中止，当销毁时会抛出ThreadAbortException异常。<br /><br /><strong>线程优先级</strong><br />　　System.Threading.Thread.Priority枚举了线程的优先级别，从而决定了线程能够得到多少CPU时间。高优先级的线程通常会比一般优先级的线程得到更多的CPU时间，如果不止一个高优先级的线程，操作系统将在这些线程之间循环分配CPU时间。低优先级的线程得到的CPU时间相对较少，当这里没有高优先级的线程，操作系统将挑选下一个低优先级 的线程执行。一旦低优先级的线程在执行时遇到了高优先级的线程，它将让出CPU给高优先级的线程。新创建的线程优先级为一般优先级，我们可以设置线程的优先级别的值，如下面所示：<br /></p>
		<p class="code">　　Highest <br />　　AboveNormal <br />　　Normal <br />　　BelowNormal <br />　　Lowest</p>
		<p>
				<br />
				<strong>结论</strong>：在这一部分，我们讨论了线程的创建何线程的优先级。System.Threading命名空间还包含了线程锁定、线程同步何通讯、多线程管理类以及死锁解决等等高级特性，在后面的部分我们将继续讨论这些内容。</p>
<img src ="http://www.cppblog.com/xingmuxixi/aggbug/16094.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xingmuxixi/" target="_blank">醒目西西</a> 2006-12-07 15:03 <a href="http://www.cppblog.com/xingmuxixi/articles/16094.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用 .NET Remoting 实现并行计算 [转] </title><link>http://www.cppblog.com/xingmuxixi/articles/16092.html</link><dc:creator>醒目西西</dc:creator><author>醒目西西</author><pubDate>Thu, 07 Dec 2006 07:02:00 GMT</pubDate><guid>http://www.cppblog.com/xingmuxixi/articles/16092.html</guid><wfw:comment>http://www.cppblog.com/xingmuxixi/comments/16092.html</wfw:comment><comments>http://www.cppblog.com/xingmuxixi/articles/16092.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xingmuxixi/comments/commentRss/16092.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xingmuxixi/services/trackbacks/16092.html</trackback:ping><description><![CDATA[Eric Bergman-Terrell <br />.NET Remoting 使您可以跨多台计算机轻松进行分布计算，只需完成非常少的编程工作。在本文中，Eric Bergman-Terrell 创建了一个名为 Digits of Pi 的应用程序，它使用并行的多台计算机以不可思议的精度计算 p 值。他设法在 12 小时内完成了 10,000 位数的计算，却只使用了相当少的计算资源。这比用一台计算机单独完成计算快了 300％。<br /><br />单击下载文件下载示例应用程序源代码后，打开 Everything.sln 解决方案。此解决方案包含运行“Digits of Pi”应用程序所需的三个项目（Client、Server 和 ServerLoader）。还包含一个名为 SimpleClient 的项目，我们稍后再讨论它。加载 Everything.sln 之后，请选择 Build（编译）| Batch Build...（批编译...）。单击 Select All（全部选定）按钮，然后单击 Build（编译）。编译所有内容后，请在本地计算机以及您的 LAN 中的远程计算机上安装该软件。<br /><br />在本地计算机上，创建一个文件夹并将以下文件复制到其中：<br /><br />Server\bin\Release\Plouffe_Bellard.dll<br />Client\bin\Release\DigitsOfPi.exe<br /><br />在每个远程计算机和本地计算机上，创建一个文件夹并将以下文件复制到其中：<br /><br />Server\bin\Release\Plouffe_Bellard.dll<br />ServerLoader\bin\Release\ServerLoader.exe<br />ServerLoader\ServerLoader.exe.config<br /><br />然后运行 ServerLoader.exe 程序。当然，运行 ServerLoader 和 Digits of Pi 程序之前，需要在每台计算机上安装 .NET Framework。<br /><br />在所有远程计算机和本地计算机上运行 ServerLoader 程序后，请运行 Digits of Pi 程序。单击 Configure...（配置...）（参见图 1），添加本地计算机名和远程计算机名。如果不确定某台计算机的名称，请查看 ServerLoader 程序，它在表中显示其计算机名。如果您很幸运地拥有一个多 CPU 系统，您只需为所有 CPU 输入一次计算机名。只需在计算机名后键入 @ 符号和一个编号。例如，如果您拥有一个名为“Brainiac”的双 CPU 系统，则键入以下计算机名：“Brainiac@1”和“Brainiac@2”。不必为多个 CPU 系统输入多个计算机名，但是这样做可以确保所有计算机的 CPU 都用于计算 p 值。输入所有计算机名后，单击 OK（确定）。<br /><br />然后指定要计算的位数（参见图 2）并单击 Calculate（计算）。请从较少的位数开始，p 值小数点后面的位数越多，程序所需的时间就越长。<br /><br />图 3 显示了 Digits of Pi 程序如何在本地计算机和远程计算机中分配工作量，它使用 TCP/IP 端口 9000 发送请求并接收结果。接下来，我们将详细探讨 Remoting、Plouffe_Bellard 服务器对象、ServerLoader 程序、SimpleClient 程序和 Digits of Pi 程序。<br /><br />Remoting 基础<br />.NET Remoting 使对象可以与其他对象通信，无论它们运行在同一台计算机上还是运行在远程计算机上。.NET Remoting 与 Web 服务非常类似，但是 .NET Remoting 技术更适于 Digits of Pi 这种完全以 .NET 编程语言编写的应用程序，并且只能在运行 .NET Framework 的计算机上运行。请参阅本文末尾“其他资源”中的“ASP.NET Web Services or .NET Remoting: How to Choose”，对两种技术进行比较。 <br /><br />您可以通过以下步骤使用 .NET Remoting 访问远程对象：<br /><br />创建从 System.MarshalByRefObject 继承的 .NET 服务器对象 (DLL)。该服务器对象将在远程计算机和本地计算机上运行。 <br />创建通过调用 RemotingConfiguration.Configure 加载服务器对象的服务器加载器程序。服务器加载器程序也将在远程计算机和本地计算机上运行。 <br />创建使用 Activator.GetObject 访问服务器对象的客户端程序。您需要添加对服务器对象的引用以编译此程序。此客户端程序只在本地计算机上运行。 <br />服务器对象<br />服务器对象将计算指定的九位 p 值。它被命名为 Plouffe_Bellard，因为它使用 Fabrice Bellard 的增强的 Simon Plouffe 算法。虽然存在更快的算法，但 Plouffe-Bellard 算法非常简单（少于 300 行源代码），它使用少量的内存，并且由于九位数字可以单独计算，因此更适于并行执行。Plouffe_Bellard.CalculatePiDigits 方法将计算在指定位置开始的九位 p 值。例如，CalculatePiDigits(1) 从第一位开始返回九位数字：141592653。CalculatePiDigits(10) 从第十位开始返回九位数字，依此类推。 <br /><br />ServerLoader<br />ServerLoader 程序将加载服务器对象，指定通过 LAN 访问服务器对象的协议和端口，侦听来自客户端程序的传入调用，处理调用并返回结果。特别值得注意的是，所有这些只需一行代码便可完成，只需通过使用配置文件的路径调用 RemotingConfiguration.Configure 方法。ServerLoader 程序将加载名为 ServerLoader.exe.config 的配置文件（参见表 1）。此配置文件指定以 SingleCall 模式加载服务器对象，即每个传入调用都由服务器对象的一个新实例处理。如果服务器对象以 Singleton 模式加载，每个传入调用都将由同一个实例处理。类型属性指定服务器对象的完整类型名称（包括 PB 命名空间）及其程序集的名称。objectUri 属性指定对象的统一资源标识符 (URI) 的端点。&lt;channel&gt; 元素指定使用 TCP 协议，端口 9000 访问服务器对象。 <br /><br />表 1：ServerLoader.exe.config。<br /><br />&lt;configuration&gt; <br />  &lt;system.runtime.remoting&gt;  <br />    &lt;application name = "ServerLoader"&gt;  <br />      &lt;service&gt; <br />        &lt;wellknown <br />          mode="SingleCall" <br />          type="PB.Plouffe_Bellard,Plouffe_Bellard"<br />          objectUri="Plouffe_Bellard"/&gt; <br />      &lt;/service&gt; <br />      &lt;channels&gt; <br />        &lt;channel ref="tcp server" port="9000"/&gt;<br />      &lt;/channels&gt; <br />    &lt;/application&gt; <br />  &lt;/system.runtime.remoting&gt;<br />&lt;/configuration&gt; <br /><br />SimpleClient<br />我创建了一个名为 SimpleClient 的程序，以说明客户端程序访问远程计算机上的服务器对象是多么容易。要运行 SimpleClient，首先在远程计算机上运行 ServerLoader，然后在本地计算机上运行 SimpleClient.exe 程序。在 Remote Machine（远程计算机）文本框中输入远程计算机的名称，然后单击 Calculate（计算）按钮开始计算第一个九位 p 值。SimpleClient 的 CalculateButton_Click 方法包含客户端访问远程服务器所需的所有代码（参见表 2）。可以使用由远程计算机名、协议 (TCP) 和端口号 (9000) 组成的 URL 访问远程服务器。例如，要访问我的“Pentium 200”计算机，则 URL 为 tcp://Pentium 200:9000/ServerLoader/Plouffe_Bellard。创建 URL 后，将使用服务器的类型 (Plouffe_Bellard) 和 URL 调用 Activator.GetObject。然后，返回的值被转换为 Plouffe_Bellard 对象以备使用。调用其 CalculatePiDigits 方法时，请求被发送到远程计算机上的 ServerLoader。然后，服务器对象计算小数位。最后，在一个文本框中显示返回客户端程序的结果。 <br /><br />表 2：用于访问远程服务器的 SimpleClient 代码。<br /><br />private void CalculateButton_Click(object sender, <br />                              System.EventArgs e)<br />{<br />  Cursor.Current = Cursors.WaitCursor;<br /><br />  Plouffe_Bellard PiCalculator = null;<br /><br />  String MachineName = RemoteMachineTextBox.Text;<br /><br />  try<br />  {<br />    int port = 9000;<br /><br />    String URL = "tcp://" + MachineName + ":" + <br />       port + "/ServerLoader/Plouffe_Bellard";<br />    PiCalculator = (Plouffe_Bellard) <br />       Activator.GetObject(typeof(Plouffe_Bellard), URL);<br />    ResultsTextBox.Text = "3." + <br />       PiCalculator.CalculatePiDigits(1);<br />  }<br />  catch(Exception)<br />  {<br />    MessageBox.Show(<br />       "需要在计算机 " +<br />       MachineName, "Simple Client 上运行 ServerLoader.exe", <br />       MessageBoxButtons.OK, MessageBoxIcon.Error);<br />  }<br /><br />  Cursor.Current = Cursors.Arrow;<br />}<br /><br />Digits of Pi 客户端<br />Digits of Pi 客户端程序比 SimpleClient 更复杂。SimpleClient 仅通过访问远程计算机上的服务器对象来计算前九位 p 值。而 Digits of Pi 则同时使用 Configure（配置）对话框中指定的远程计算机和本地计算机（如图 1 所示）并行计算用户指定的小数位。服务器对象在单独的线程中访问，以便在可能需要很长时间的计算过程中保持 Digits of Pi GUI 对用户操作的响应性。 <br /><br />Digits of Pi 使用数组将作业分为九位数据块，将工作量分配到所有可用的计算机上。用户单击 Calculate（计算）按钮后，将创建 SolutionArray（参见图 4）。SolutionArray 为要计算的每组九位 p 值分配一个 SolutionItem 元素。服务器对象计算 m_Digit 字段指定的九位数组后，数位将存储在 m_Results 成员中。m_MachineName 成员包含运行服务器的计算机的名称。存储计算机名是为了使 Digits of Pi 能够显示每台计算机计算的小数总数（参见图 2）。<br /><br />为使服务器对象并行计算，Digits of Pi 将为每个服务器对象创建一个线程并启动线程计算。然后，必须等待所有线程完成计算后才能显示最终结果。WaitHandle 对于等待多个线程很有用。Digits of Pi 将为每个线程使用一个 WaitHandle，以等待所有线程完成计算。<br /><br />将调用 CalculationThread.Calculate（参见表 3）以便为每个服务器对象创建一个线程。该操作将启动线程运行，然后返回一个 AutoResetEvent（从 WaitHandle 衍生而来）。每个线程的 AutoResetEvent 都存储在一个数组中，然后数组被传递给 WaitHandle.WaitAll。完成线程计算后，将对其 AutoResetEvent 调用 Set 方法。最后一个线程调用 Set 方法后，将返回 WaitAll 调用，并显示 p 的值。<br /><br />表 3：CalculationThread。<br /><br />public static WaitHandle Calculate(<br />SolutionArray solutionArray, String machineName)<br />{<br />  CalculationThread calculationThread = new <br />    CalculationThread(solutionArray, machineName);<br />  Thread thread = new Thread(new <br />    ThreadStart(calculationThread.Calculate));<br />  thread.Start();<br />  return calculationThread.calculationDone;<br />}<br /><br />每个线程都使用相同的算法：如果有更多的工作要处理，线程将夺取下一个 SolutionItem，在 SolutionItem 中存储服务器对象的计算机名，计算指定的九位小数，并将结果存储在 SolutionItem 中。此进程将一直运行，直到所有 SolutionItem 中都填充了结果。有关详细信息，请参见表 4。<br /><br />表 4：CalculationThread.Calculate。<br /><br />public void Calculate()<br />{<br />  Plouffe_Bellard PiCalculator = <br />    RemotePiCalculator.GetPiCalculator(<br />      GetRealMachineName(machineName));<br /><br />  if (PiCalculator != null)<br />  {<br />    SolutionItem Item = null;<br />    bool Abort;<br /><br />    do<br />    {<br />      Abort = solutionArray.Abort;<br /><br />      if (!Abort)<br />      {<br />        Item = solutionArray.GetNextItem();<br /><br />        if (Item != null)<br />        {<br />          Item.MachineName = machineName;<br /><br />          try<br />          {<br />            Item.Results = <br />           PiCalculator.CalculatePiDigits(Item.Digit);<br />          }<br />          catch (Exception e)<br />          {<br />            Abort = true;<br />            MessageBox.Show(<br />              "无法访问主机上的远程对象 " +<br />              machineName + Environment.NewLine + <br />              Environment.NewLine + "Message:  " + <br />              e.Message, Globals.ProgramName, <br />              MessageBoxButtons.OK, <br />              MessageBoxIcon.Error);<br />          }<br /><br />          UpdateStatisticsDelegate USD = new <br />            UpdateStatisticsDelegate(<br />              MF.UpdateStatistics);<br /><br />          MF.Invoke(USD, new Object[] {} <a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br />        }<br />      }<br />    } while (Item != null &amp;&amp; !Abort);<br /><br />    calculationDone.Set();<br />  }<br />}<br /><br />下面是逐步的说明：<br /><br />GetRealMachineName 从多 CPU 计算机名中删除 @1 模式。例如，GetRealMachineName("Brainiac@1"<a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a> 返回 "Brainiac"。有关多 CPU 计算机名的解释，请参见图 1 对话框中的文本。 <br />知道正确的计算机名后，将其传递给 RemotePiCalculator.GetPiCalculator，这样才可以通过 PiCalculator 变量访问该计算机上的服务器对象。 <br />如果用户单击了 Cancel（取消）按钮，将设置 Abort 属性。如果 Abort 属性为 true，线程将停止计算。 <br />对 MF.Invoke 的调用使线程可以安全地更新 ListView 中的统计数据（参见图 2），即使该 ListView 是由另一个线程创建的。在 32 位 Windows 编程中，绝不允许在创建某个控件的线程之外处理该控件。 <br />完成循环（即计算完指定的所有 p 位数或者用户单击 Cancel [取消] 按钮）后，将调用线程的 AutoResetEvent 的 Set 函数。 <br />当每个线程都调用其 AutoResetEvent 的 Set 函数后，将返回对 WaitHandle.WaitAll 的调用并显示结果。 <br />线程同步<br />如果 Digits of Pi 的代码由多个线程同时访问，可能会有多个地方出现错误。例如，如果两个线程同时调用 SolutionArray.GetNextItem，可能会返回相同的内容。这就是在 GetNextItem 方法中设置 [MethodImpl(MethodImplOptions.Synchronized)] 属性的原因，该属性可以确保一次只有一个线程调用该方法。如果方法的每一行代码都不应由多个线程同时访问，则使方法同步是一个很好的策略。 <br /><br />由于 MainForm.Calculate 方法只有一行代码不能同时被多个线程访问，因此它将在该行代码之前调用 Monitor.Enter，并在其后调用 Monitor.Exit。如果该行代码已在其他线程上运行，Monitor.Enter 将被阻止。如果整个函数已实现同步，那么只保护需要防止多个线程访问的代码行可以提高性能。<br /><br />从 System.Windows.Forms.Control 衍生的对象（例如 Button、TextBoxe、RichTextBoxe、Label、ListBoxe、ListView 等等）只应由创建它们的线程处理。要从非创建线程中安全处理 Control 衍生对象，请首先将处理代码放入一个方法，然后为该方法声明一个代理：<br /><br />delegate void SetResultsTextDelegate(String Text);<br /><br />private void SetResultsText(String Text)<br />{<br />  ResultsRichTextBox.Text = Text;<br />}<br /><br />然后使用 Form.Invoke 间接调用该方法：<br /><br />SetResultsTextDelegate SRTD = new <br />   SetResultsTextDelegate(SetResultsText);<br /><br />Invoke(SRTD, new object[] { "" } <a href="http://www.blogcn.com/images/wink.gif" target="_blank"><img src="http://www.blogcn.com/images/wink.gif" onload="if(this.width&gt;screen.width/2)this.style.width=screen.width/2;" border="0" /></a>;<br /><br />Invoke 方法将从创建它的线程中调用该方法，它使用的参数与对象数组中的元素相对应。<br /><br />小结<br />.NET Remoting 是一种在远程（和本地）计算机上执行代码的简单而有效的机制。只需将代码封装到 .NET 对象中，编写加载该对象并侦听请求的程序，然后在客户端程序中调用 Activator.GetObject。如果您的 LAN 中有一些闲置的计算机，可以利用它们轻松地解决并行问题。只需记住要使用正确的线程同步机制，以防止线程之间发生冲突。 <br /><br />下载 TERRELL.ZIP<br /><br />其他资源<br />“ASP.NET Web 服务还是 .NET Remoting：如何选择 ”(<img alt="::URL::" hspace="2" src="http://www.blogcn.com/images/aurl.gif" align="absBottom" border="0" /><a href="http://www.microsoft.com/china/msdn/library/dnbda/html/bdadotnetarch16.asp)" target="_blank">http://www.microsoft.com/china/msdn/library/dnbda/html/bdadotnetarch16.asp)</a>  一文很有用，它对 .NET Web Service 和 .NET Remoting 进行了比较。 <br />Fabrice Bellard's Pi Page (<img alt="::URL::" hspace="2" src="http://www.blogcn.com/images/aurl.gif" align="absBottom" border="0" /><a href="http://fabrice.bellard.free.fr/pi/)" target="_blank">http://fabrice.bellard.free.fr/pi/)</a>  提供了一些用于计算 p 值的有用公式和源代码，包括 Digits of Pi 程序中使用的算法的 C 语言源代码。 <br />有关远程访问程序的源代码，请访问 www.personalmicrocosms.com/html/ra.html。此程序使用 .NET Remoting 显示远程计算机的桌面，并使用本地计算机的键盘和鼠标运行远程计算机。 <br />有关数学化方面的内容，请参阅 Petr Beckmann 著的《History of Pi》（St. Martin's Press 1971 年出版），这是一本相当不错的书，因为 p 的历史就是数学历史的微观反映。Beckmann 的书涵盖了 p 的数学历史以及政治历史。 <br />Ingo Rammer 的《Advanced .NET Remoting》（Apress 2002 年出版）是有关 Remoting 的权威指南。此书看起来更适合从头到尾的详细阅读。我倒是希望此书能够适合我的“随便翻翻”的阅读习惯。 <br />有关 Hardcore Visual Studio .NET 和 Pinnacle Publishing 的详细信息，请访问它们的 Web 站点 <img alt="::URL::" hspace="2" src="http://www.blogcn.com/images/aurl.gif" align="absBottom" border="0" /><a href="http://www.pinpub.com/。" target="_blank">http://www.pinpub.com/。</a><br /><br />注意：这不是 Microsoft Corporation 的 Web 站点。Microsoft 对该站点的内容不承担责任。<br /><br />本文转载自 2003 年 4 月份的 Hardcore Visual Studio .NET。版权所有 2003 Pinnacle Publishing, Inc.（除非另行说明）。保留所有权利。Hardcore Visual Studio .NET 是 Pinnacle Publishing, Inc. 独立发行的刊物。未经 Pinnacle Publishing, Inc. 事先同意，不得以任何形式使用或复制本文的任何部分（评论文章中的简短引用除外）。如需与 Pinnacle Publishing, Inc.联系，请致电 1-800-788-1900。<br /><img src ="http://www.cppblog.com/xingmuxixi/aggbug/16092.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xingmuxixi/" target="_blank">醒目西西</a> 2006-12-07 15:02 <a href="http://www.cppblog.com/xingmuxixi/articles/16092.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[C#学习]在多线程中如何调用Winform</title><link>http://www.cppblog.com/xingmuxixi/articles/16086.html</link><dc:creator>醒目西西</dc:creator><author>醒目西西</author><pubDate>Thu, 07 Dec 2006 06:37:00 GMT</pubDate><guid>http://www.cppblog.com/xingmuxixi/articles/16086.html</guid><wfw:comment>http://www.cppblog.com/xingmuxixi/comments/16086.html</wfw:comment><comments>http://www.cppblog.com/xingmuxixi/articles/16086.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xingmuxixi/comments/commentRss/16086.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xingmuxixi/services/trackbacks/16086.html</trackback:ping><description><![CDATA[问题的产生：<br /><br /><font color="#008000">　　我的WinForm程序中有一个用于更新主窗口的工作线程（worker thread），但文档中却提示我不能在多线程中调用这个form（为什么？），而事实上我在调用时程序常常会崩掉。请问如何从多线程中调用form中的方法呢？</font><br /><br />　　解答：<br /><br />　　每一个从Control类中派生出来的WinForm类（包括Control类）都是依靠底层Windows消息和一个消息泵循环（message pump loop）来执行的。消息循环都必须有一个相对应的线程，因为发送到一个window的消息实际上只会被发送到创建该window的线程中去。其结果是，即使提供了同步（synchronization），你也无法从多线程中调用这些处理消息的方法。大多数plumbing是掩藏起来的，因为WinForm是用代理（delegate）将消息绑定到事件处理方法中的。WinForm将Windows消息转换为一个基于代理的事件，但你还是必须注意，由于最初消息循环的缘故，只有创建该form的线程才能调用其事件处理方法。如果你在你自己的线程中调用这些方法，则它们会在该线程中处理事件，而不是在指定的线程中进行处理。你可以从任何线程中调用任何不属于消息处理的方法。<br /><br />　　Control类（及其派生类）实现了一个定义在System.ComponentModel命名空间下的接口 -- ISynchronizeInvoke，并以此来处理多线程中调用消息处理方法的问题：<br /><br /><table cellspacing="0" cellpadding="0" width="100%" bgcolor="#ffffff" border="0"><tbody><tr><td><strong><font color="#000080">public interface ISynchronizeInvoke<br />{<br />　object Invoke(Delegate　method,object[] args);<br />　IAsyncResult BeginInvoke(Delegate　method,object[] args);<br />　object EndInvoke(IAsyncResult result);<br />　bool InvokeRequired {get;}<br />}</font></strong></td></tr></tbody></table><br />　　ISynchronizeInvoke提供了一个普通的标准机制用于在其他线程的对象中进行方法调用。例如，如果一个对象实现了ISynchronizeInvoke，那么在线程T1上的客户端可以在该对象中调用ISynchronizeInvoke的Invoke()方法。Invoke()方法的实现会阻塞（block）该线程的调用，它将调用打包发送（marshal）到 T2，并在T2中执行调用，再将返回值发送会T1，然后返回到T1的客户端。Invoke()方法以一个代理来定位该方法在T2中的调用，并以一个普通的对象数组做为其参数。<br /><br />　　调用者还可以检查InvokeRequired属性，因为你既可以在同一线程中调用ISynchronizeInvoke也可以将它重新定位（redirect）到其他线程中去。如果InvokeRequired的返回值是false的话，则调用者可以直接调用该对象的方法。<br /><br />　　比如，假设你想要从另一个线程中调用某个form中的Close方法，那么你可以使用预先定义好的的MethodInvoker代理，并调用Invoke方法:<br /><br /><table cellspacing="0" cellpadding="0" width="100%" bgcolor="#ffffff" border="0"><tbody><tr><td><font color="#000080">Form form;<br />/* obtain a reference to the form, <br />then: */<br />ISynchronizeInvoke synchronizer;<br />synchronizer = form;<br /><br />if(synchronizer.InvokeRequired)<br />{<br />MethodInvoker invoker = new <br />MethodInvoker(form.Close);<br />synchronizer.Invoke(invoker,null);<br />}<br />else<br />form.Close();</font></td></tr></tbody></table><br />　　ISynchronizeInvoke不仅仅用于WinForm中。例如，一个Calculator类提供了将两个数字相加的Add()方法，它就是通过ISynchronizeInvoke来实现的。用户必须确定ISynchronizeInvoke.Invoke()方法的调用是执行在正确的线程中的。<br /><br />　　C# 在正确的线程中写入调用<br /><br />　　列表A. Calculator类的Add()方法用于将两个数字相加。如果用户直接调用Add()方法，它会在该用户的线程中执行调用，而用户可以通过ISynchronizeInvoke.Invoke()将调用写入正确的线程中。 
<p>　　列表A:<br /></p><table cellspacing="0" cellpadding="0" width="100%" bgcolor="#ffffff" border="0"><tbody><tr><td><p><font color="#000080">public class Calculator : ISynchronizeInvoke<br />{<br />　public int Add(int arg1,int arg2)<br />　{　<br />　　int threadID = Thread.CurrentThread.GetHashCode();<br />　　Trace.WriteLine( "Calculator thread ID is " + threadID.ToString());<br />　　return arg1 + arg2;<br />　}<br />　//ISynchronizeInvoke implementation <br />　public object Invoke(Delegate method,object[] args)<br />　{<br />　　public IAsyncResult BeginInvoke(Delegate method,object[] args)<br />　　{<br />　　　public object EndInvoke(IAsyncResult result)<br />　　　{<br />　　　　public bool InvokeRequired<br />　　　　{<br />　　　　}<br />　　　}<br />　　　//Client-side code<br />　　　public delegate int AddDelegate(int arg1,int arg2);</font></p><p><font color="#000080">　　　　int threadID = Thread.CurrentThread.GetHashCode();<br />　　　　Trace.WriteLine("Client thread ID is " + threadID.ToString());</font></p><p><font color="#000080">　　　　Calculator calc;<br />　　　　/* Some code to initialize calc */</font></p><p><font color="#000080">　　　　AddDelegate addDelegate = new AddDelegate(calc.Add);</font></p><p><font color="#000080">　　　　object[] arr = new object[2];<br />　　　　arr[0] = 3;<br />　　　　arr[1] = 4;</font></p><p><font color="#000080">　　　　int sum = 0;<br />　　　　sum = (int) calc.Invoke(addDelegate,arr);<br />　　　　Debug.Assert(sum ==7);</font></p><p><font color="#000080">　　　　/* Possible output:<br />　　　　Calculator thread ID is 29<br />　　　　Client thread ID is 30 <br />　　　　*/</font></p></td></tr></tbody></table><p>　　或许你并不想进行同步调用，因为它被打包发送到另一个线程中去了。你可以通过BeginInvoke()和EndInvoke()方法来实现它。你可以依照通用的.NET非同步编程模式（asynchronous programming model）来使用这些方法：用BeginInvoke()来发送调用，用EndInvoke()来实现等待或用于在完成时进行提示以及收集返回结果。<br /><br />　　还值得一提的是ISynchronizeInvoke方法并非安全类型。 类型不符会导致在执行时被抛出异常，而不是编译错误。所以在使用ISynchronizeInvoke时要格外注意，因为编辑器无法检查出执行错误。<br /><br />　　实现ISynchronizeInvoke要求你使用一个代理来在后期绑定（late binding）中动态地调用方法。每一种代理类型均提供DynamicInvoke()方法： public object DynamicInvoke(object[] <br />args);<br /><br />　　理论上来说，你必须将一个方法代理放到一个需要提供对象运行的真实的线程中去，并使Invoke() 和BeginInvoke()方法中的代理中调用DynamicInvoke()方法。ISynchronizeInvoke的实现是一个非同一般的编程技巧，本文附带的源文件中包含了一个名为Synchronizer的帮助类（helper class）和一个测试程序，这个测试程序是用来论证列表A中的Calculator类是如何用Synchronizer类来实现ISynchronizeInvoke的。Synchronizer是ISynchronizeInvoke的一个普通实现，你可以使用它的派生类或者将其本身作为一个对象来使用，并将ISynchronizeInvoke实现指派给它。 <br /><br />　　用来实现Synchronizer的一个重要元素是使用一个名为WorkerThread的嵌套类（nested class）。WorkerThread中有一个工作项目（work item）查询。WorkItem类中包含方法代理和参数。Invoke()和BeginInvoke()用来将一个工作项目实例加入到查询里。WorkerThread新建一个.NET worker线程，它负责监测工作项目的查询任务。查询到项目之后，worker会读取它们，然后调用DynamicInvoke()方法。</p><img src ="http://www.cppblog.com/xingmuxixi/aggbug/16086.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xingmuxixi/" target="_blank">醒目西西</a> 2006-12-07 14:37 <a href="http://www.cppblog.com/xingmuxixi/articles/16086.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>