??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品久久一区二区三区,国产精品亚洲综合专区片高清久久久,久久中文字幕人妻熟av女http://www.shnenglu.com/xingmuxixi/category/3298.htmlzh-cnTue, 15 Jul 2008 06:27:50 GMTTue, 15 Jul 2008 06:27:50 GMT60C++基本cd对象化的一个方?/title><link>http://www.shnenglu.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.shnenglu.com/xingmuxixi/articles/55796.html</guid><wfw:comment>http://www.shnenglu.com/xingmuxixi/comments/55796.html</wfw:comment><comments>http://www.shnenglu.com/xingmuxixi/articles/55796.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/xingmuxixi/comments/commentRss/55796.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/xingmuxixi/services/trackbacks/55796.html</trackback:ping><description><![CDATA[<p><strong>1.问题</strong><br> 在很多用C++开发服务器产品Ӟ需要将不同的数据类型存储到一个容器中(有点cMHttpSession可以保存会话期间Lcd的数?Q供其它使用E序查找?br> 在Java和C#中这是一个简单的问题Q可以用Object对象来实现类型无关的数据l构Qƈ且很好的解决了内存回收等问题?br> 但C++中很隑ց到这一点,C++是一门静态类型语aQ没有一个所有类型的基类?/p> <p><br><strong>2.一般方?/strong><br> 一般解册个问题的办法是用void*指针来存储数据,象下面的代码Q?br> map<string,void*><br> 但是q样带来几个问题Q?br> Q?Q因为C++在不知道cȝ型时无法正确的释攑ֆ存;<br> Q?Q很多用者用它Ӟ释放内存的时机难于确定;</p> <p><br><strong>3.让它正确释放内存</strong><br> 我们可以定义一个公q基类Q让所有需要放到容器的cdl承?br> class Object<br> {<br> public:<br>  virtual ~Object(){cout<<"Object Destroy" << endl;}<br> };<br> ׃使用了virtual析构函数因此可以保delete obj的时可以正常工作。因此上面的容器定义变成了这P<br> map<string,Object*></p> <p><br><strong>4.让它知道何时释放内存</strong><br> 大家都知道,q时必须使用引用计数Q不q很q运有现成的Q我们用boost::share_ptr<br> map<string,boost::share_ptr<Object*> ><br> 很好两个问题都已l解冻I但如何向他们中加入C++的基本类型呢Q?/p> <p><br><strong>5.开发基本类型的装c?/strong><br> 基本cd很多Q如果每一个都写一个类Q太累了Q我们可以定义一个模板,q里的难Ҏ基本cd之间的操作符重蝲Q不同类型之间的q算q回的类型ƈ不相同,q就需要写很多重蝲函数Q在q里我们使用Loki来简化这些操作。用Loki的TypeList来自动计应该是什么返回?br> #include"Typelist.h" //Loki头文?br> template <typename T><br> class PrimerType:public Object<br> {<br> public:<br>  typedef T value_type;//基本cd<br>  typedef PrimerType<T> class_type;//基本cd的对象类?br> <br> public:<br>  PrimerType()<br>   :m_value((value_type)0)<br>  {<br>  }<br> <br>  template<typename Other><br>   PrimerType(const Other& value)<br>   :m_value(value)<br>  {<br>  }<br> <br>  ~PrimerType()<br>  {<br>   cout<<"PrimerType Destroy" << endl;<br>  }<br> <br>  //基本cd转换操作W重?br>  operator value_type() const<br>  {<br>   return m_value;<br>  }<br> <br>  //赋值操作符重蝲<br>  const class_type& operator=(value_type value)<br>  {<br>   m_value=value;<br>   return *this;<br>  }<br> <br>  bool operator!( ) const <br>  {<br>   return !m_value;<br>  }<br> <br>  //作ؓcL员的术q算W操作符重蝲<br>  class_type& operator++()<br>  {// ++ 前缀<br>   m_value+=1;<br>   return *this;<br>  }<br>  const class_type operator++(int)<br>  {// ++ 后缀 <br>   class_type oldValue=*this;<br>   m_value+=1;<br>   return oldValue;<br>  }<br>  class_type& operator--()<br>  {// -- 前缀<br>   m_value-=1;<br>   return *this;<br>  }<br>  const class_type operator--(int)<br>  {// -- 后缀 <br>   class_type oldValue=*this;<br>   m_value-=1;<br>   return oldValue;<br>  }<br> <br>  class_type& operator+=(const value_type& value)<br>  {<br>   m_value+=value;<br>   return *this;<br>  }<br>  //。。。省?= /= *= &= |= ^= %= {等<br> private:<br>  value_type m_value;<br>  friend istream& operator>><T> ( istream& is, class_type& ptvalue );<br> };<br> <br> //输入函敎ͼ不用输出Q通过cd操作W重载自动完成)<br> template<typename T><br> istream& operator>> ( istream& is, PrimerType<T>& ptvalue )<br> {<br>  is >> ptvalue.m_value;<br>  return is;<br> }<br> //基本cd重定?br> typedef __int8  int8;<br> typedef __int16 int16;<br> typedef __int32 int32;<br> typedef __int64 int64;<br> typedef unsigned __int8 uint8;<br> typedef unsigned __int16 uint16;<br> typedef unsigned __int32 uint32;<br> typedef unsigned __int64 uint64;<br> <br> <br> //基本cd的对象类?br> typedef PrimerType<bool>   Boolean;<br> typedef PrimerType<int8>   Int8;<br> typedef PrimerType<int16>   Int16;<br> typedef PrimerType<int32>   Int32;<br> typedef PrimerType<int64>   Int64;<br> typedef PrimerType<uint8>   UInt8;<br> typedef PrimerType<uint16>   UInt16;<br> typedef PrimerType<uint32>   UInt32;<br> typedef PrimerType<uint64>   UInt64;<br> typedef PrimerType<float>   Float;<br> typedef PrimerType<double>   Double;<br> typedef PrimerType<long>   Long;<br> typedef PrimerType<unsigned long> ULong;<br> //更友好的名字<br> typedef Int8     Char;<br> typedef Int16     Short;<br> typedef Int32     Int;<br> typedef UInt8     Byte;<br> typedef UInt16     UShort;<br> typedef UInt32     UInt;<br> <br> <font color=#0000ff>//术q算q回cd的traitsQ运时以排在后面的cdq回<br> #define  PRIMERTYPELIST TYPELIST_13(bool,int8,uint8,int16,uint16,int32,uint32,long,unsigned long,int64,uint64,float,double)<br> //                 |<br> //                 int<br> template <typename T1, typename T2><br> struct ResultType_Traits<br> {<br>  enum { lefttype_index =::Loki::TL::IndexOf<PRIMERTYPELIST,T1>::value};<br>  enum { righttype_index =::Loki::TL::IndexOf<PRIMERTYPELIST,T2>::value};<br>  enum { resulttype_index = (lefttype_index>righttype_index)?lefttype_index:righttype_index};</p> //在vc7.1下int32以前的类型做术q算都返回int32cd<br>  typedef typename ::Loki::TL::TypeAt<PRIMERTYPELIST, (resulttype_index<5)?5:resulttype_index >::Result  result_type;<br> };</font><br> <br> //作ؓ全局的算术运符操作W重?+ - * /<br> template<typename T1,typename T2><br> <font color=#0000ff>typename ResultType_Traits<T1,T2>::result_type</font> operator +(const PrimerType<T1>& lhs,const T2& rhs)<br> {<br>  return (T1)lhs+rhs;<br> }<br> <br> template<typename T1,typename T2><br> <font color=#0000ff>typename ResultType_Traits<T1,T2>::result_type</font> operator +(const T1& lhs,const PrimerType<T2>& rhs)<br> {<br>  return lhs+(T2)rhs;<br> }<br> <br> template<typename T1,typename T2><br> <font color=#0000ff>typename ResultType_Traits<T1,T2>::result_type</font> operator +(const PrimerType<T1>& lhs,const PrimerType<T2>& rhs)<br> {<br>  return (T1)lhs+(T2)rhs;<br> }<br> //。。。省?- * /{等<br> <br> // 逻辑q算W重?br> template<typename T1,typename T2><br> bool operator ==(const PrimerType<T1>& lhs,const T2& rhs)<br> {<br>  return (T1)lhs==rhs;<br> }<br> <br> template<typename T1,typename T2><br> bool operator ==(const T1& lhs,const PrimerType<T2>& rhs)<br> {<br>  return lhs==(T2)rhs;<br> }<br> <br> template<typename T1,typename T2><br> bool operator ==(const PrimerType<T1>& lhs,const PrimerType<T2>& rhs)<br> {<br>  return (T1)lhs==(T2)rhs;<br> }<br> //。。。省?!= >= {等<br> <br> <br>6.结<br> 使用对象来表C基本类型,׃使用了virtual的析构它是有内存费的,但在很多应用中它是很有用的?br> 同时你可以增加String/DateTime的特化支持,q样完整了<br></font> <img src ="http://www.shnenglu.com/xingmuxixi/aggbug/55796.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/xingmuxixi/" target="_blank">醒目西西</a> 2008-07-10 14:44 <a href="http://www.shnenglu.com/xingmuxixi/articles/55796.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]delegate ?多线E?http://www.shnenglu.com/xingmuxixi/articles/16694.html醒目西西醒目西西Thu, 21 Dec 2006 08:05:00 GMThttp://www.shnenglu.com/xingmuxixi/articles/16694.htmlhttp://www.shnenglu.com/xingmuxixi/comments/16694.htmlhttp://www.shnenglu.com/xingmuxixi/articles/16694.html#Feedback0http://www.shnenglu.com/xingmuxixi/comments/commentRss/16694.htmlhttp://www.shnenglu.com/xingmuxixi/services/trackbacks/16694.html 很多时候写 windows E序都需要结合多U程Q在 .net 中用如下得代码来创徏q启动一个新的线E?/span>

public void ThreadProc();

Thread thread = new Thread( new ThreadStart( ThreadProc ) );

thread.IsBackground = true;

thread.Start();

但是很多时候,在新的线E中Q我们需要与 UI q行交互Q在 .net 中不允许我们直接q样做。可以参?/span> MSDN 中的描述Q?/span>

“Windows H体?/span>使用单线E单?span lang="EN-US"> (STA) 模型Q因?span lang="EN-US">“Windows H体?/span>Z本机 Win32 H口Q?span lang="EN-US"> Win32 H口从本质上而言是单元线E?span lang="EN-US">STA 模型意味着可以在Q何线E上创徏H口Q但H口一旦创建后׃能切换线E,q且对它的所有函数调用都必须在其创徏U程上发生。除?span lang="EN-US"> Windows H体之外Q?span lang="EN-US">.NET Framework 中的cM用自qE模型?span lang="EN-US">

STA 模型要求需从控件的非创建线E调用的控g上的MҎ必须被封送到Q在其上执行Q该控g的创建线E。基c?span lang="EN-US"> Control 为此目的提供了若q方法(Invoke?span lang="EN-US">BeginInvoke ?span lang="EN-US"> EndInvokeQ?b>Invoke生成同步Ҏ调用Q?b>BeginInvoke生成异步Ҏ调用?span lang="EN-US">

Windows H体中的控g被绑定到特定的线E,不具备线E安全性。因此,如果从另一个线E调用控件的ҎQ那么必M用控件的一?span lang="EN-US"> Invoke Ҏ来将调用送到适当的线E?span lang="EN-US">

正如所看到的,我们必须调用 Invoke ҎQ?/span> BeginInvoke 可以认ؓ?/span> Invoke 的异步版本。调用方法如下:

public delegate void OutDelegate(string text);

public void OutText(string text)

{

     txt.AppendText(text);

     txt.AppendText( "\t\n" );

}

OutDelegate outdelegate = new OutDelegate( OutText );

this .BeginInvoke(outdelegate, newobject[]{text});

如果我们需要在另外一个线E里面对 UI q行操作Q我们需要一个类?/span> OutText 的函敎ͼq需要一个该函数的委?/span> delegate Q当Ӟq里展示的是自定义的Q?/span> .net 中还有很多其他类型的委托Q可以直接用,不需要而外声明。例如: MethodInvoker ?/span> EventHandler Q这两种cd委托的函数外观是固定的, MethodInvoker ?/span> void Function() cd的委托,?/span> EventHandler ?/span> void Function(object, EventArgs) cd的委托,W一个不支持参数Q第二中的参数类型和数量都是固定的,q两U委托可以很方便的调用,但是~Z灉|性。请注意 BeginInvoke 前面的对象是 this Q也是ȝE。现在再介绍 Control.InvokeRequired Q?/span> Control 是所有控件的基类Q对于这个属?/span> MSDN 的描q是Q?/span>

获取一个|该值指C用方在对控gq行Ҏ调用时是否必调?/span> Invoke ҎQ因用方位于创徏控g所在的U程以外的线E中?/span>

该属性可用于定是否必须调用 Invoke ҎQ当不知道什么线E拥有控件时q很有用?/span>

也就是说通过判断 InvokeRequired 可以知道是否需要用委托来调用当前控件的一些方法,如此可以?/span> OutText 函数修改一下:

public delegate void OutDelegate(string text);

public void OutText(string text)

{

     if( txt.InvokeRequired )

     {

         OutDelegate outdelegate = new OutDelegate( OutText );

         this.BeginInvoke(outdelegate, newobject[]{text});

         return;

     }

     txt.AppendText(text);

     txt.AppendText( "\t\n" );

}

注意Q这里的函数没有q回Q如果有q回Q需要调?/span> Invoke 或?/span> EndInvoke 来获得返回的l果Q不要因为包装而丢׃q回倹{如果调用没有完成, Invoke ?/span> EndInvoke 都将会引起阻塞?/span>

现在如果我有一个线E函数如下:

public void ThreadProc()

{

     for(int i = 0; i < 5; i++)

     {

         OutText( i.ToString() );

         Thread.Sleep(1000);

     }

}

如果循环的次数很大,或者漏?/span> Thread.Sleep(1000); Q那么你?/span> UI 肯定会停止响应,想知道原因吗Q看?/span> BeginInvoke 前面的对象,没错Q就?/span> this Q也是ȝE,当你的主U程不停的调?/span> OutText 的时候, UI 当然会停止响应?/span>

 

与以?/span> VC 中创Z个新的线E需要调?/span> AfxBeginThread 函数Q该函数中第一个参数就是线E函数的地址Q而第二个参数是一个类型ؓ LPVOID 的指针类型,q个参数传递给U程函数。现在我们没有办法再使用q种Ҏ来传递参C。我们需要将传递给U程的参数和U程函数包装成一个单独的c,然后在这个类的构造函C初始化该U程所需的参敎ͼ然后再将该实例的U程函数传递给 Thread cȝ构造函数。代码大致如下:

public class ProcClass

{

     private string procParameter = "";

     public ProcClass(string parameter)

     {

         procParameter = parameter;

     }

     public void ThreadProc()

     {

     }

}

ProcClass threadProc = new ProcClass("use thread class");

Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );

thread.IsBackground = true;

thread.Start();

是q样Q需要徏立一个中间类来传递线E所需的参数?/span>

那么如果我的U程又需要参敎ͼ又需要和 UI q行交互的时候该怎么办呢Q可以修改一下代码:

public class ProcClass

{

     private string procParameter = "";

     private Form1.OutDelegate delg = null;

     public ProcClass(string parameter, Form1.OutDelegate delg)

     {

         procParameter = parameter;

         this.delg = delg;

     }

     public void ThreadProc()

     {

         delg.BeginInvoke("use ProcClass.ThreadProc()", null, null);

     }

}

ProcClass threadProc = new ProcClass("use thread class", new OutDelegate(OutText));

Thread thread = new Thread( new ThreadStart( threadProc.ThreadProc ) );

thread.IsBackground = true;

thread.Start();

q里只是我的一些理解,如果有什么错误或者不当的地方Q欢q指出?/span>



醒目西西 2006-12-21 16:05 发表评论
]]>
去腾讯时遇到的一个面试题http://www.shnenglu.com/xingmuxixi/articles/16551.html醒目西西醒目西西Sun, 17 Dec 2006 07:33:00 GMThttp://www.shnenglu.com/xingmuxixi/articles/16551.htmlhttp://www.shnenglu.com/xingmuxixi/comments/16551.htmlhttp://www.shnenglu.com/xingmuxixi/articles/16551.html#Feedback1http://www.shnenglu.com/xingmuxixi/comments/commentRss/16551.htmlhttp://www.shnenglu.com/xingmuxixi/services/trackbacks/16551.html * 分离字符?br /> * q个cȝ功能Q是把指定的字符Ԍ以‘|’ؓ界,把字W串分离
 * 去腾讯面试手机开发的时候遇到的面试题,当时׃对java语言l节不熟悉,
 * 没做出来Q所以一直耿耿于怀
 * ׃使用了String和ListQ得用java实现变得很简?br /> * 用c实现才是王道
 */

醒目西西 2006-12-17 15:33 发表评论
]]>
腾讯最新面试题,法高手误http://www.shnenglu.com/xingmuxixi/articles/16545.html醒目西西醒目西西Sun, 17 Dec 2006 07:31:00 GMThttp://www.shnenglu.com/xingmuxixi/articles/16545.htmlhttp://www.shnenglu.com/xingmuxixi/comments/16545.htmlhttp://www.shnenglu.com/xingmuxixi/articles/16545.html#Feedback6http://www.shnenglu.com/xingmuxixi/comments/commentRss/16545.htmlhttp://www.shnenglu.com/xingmuxixi/services/trackbacks/16545.html1,两个整数集合A,B,求其交集,要求写出代码;
2,求一个论坛的在线人数,假设有一个论?其注册ID有两忆个,每个ID从登陆到退Z向一个日志文件中C登陆旉和退出时?要求写一个算法统计一天中论坛的用户在U分?取样_度为秒.

醒目西西 2006-12-17 15:31 发表评论
]]>
一道腾讯的面试?http://www.shnenglu.com/xingmuxixi/articles/16542.html醒目西西醒目西西Sun, 17 Dec 2006 07:30:00 GMThttp://www.shnenglu.com/xingmuxixi/articles/16542.htmlhttp://www.shnenglu.com/xingmuxixi/comments/16542.htmlhttp://www.shnenglu.com/xingmuxixi/articles/16542.html#Feedback2http://www.shnenglu.com/xingmuxixi/comments/commentRss/16542.htmlhttp://www.shnenglu.com/xingmuxixi/services/trackbacks/16542.html{
word m_a1;
word m_a2;
a(){m_a1=1;m_a2=2;}
void fun(){printf("%d,%d",m_a1,m_a2);}
}
class b
{
dword m_a3;
b(){m_a3=3;}
void fun(){printf("%d",m_a3);}
}
main()
{
a a;
b *pb;
pb=b*(&a);
pb->fun();
}
输出是什么?


醒目西西 2006-12-17 15:30 发表评论
]]>
c#多线E教?4):U程池和异步~程http://www.shnenglu.com/xingmuxixi/articles/16096.html醒目西西醒目西西Thu, 07 Dec 2006 07:05:00 GMThttp://www.shnenglu.com/xingmuxixi/articles/16096.htmlhttp://www.shnenglu.com/xingmuxixi/comments/16096.htmlhttp://www.shnenglu.com/xingmuxixi/articles/16096.html#Feedback0http://www.shnenglu.com/xingmuxixi/comments/commentRss/16096.htmlhttp://www.shnenglu.com/xingmuxixi/services/trackbacks/16096.html如果你仔l阅M我前面的三篇文章,我相信你对用.NET Framework提供的System.Threading.Threadcd一些线E同步的cd本的U程知识和多U程~程知识很了解。我们将在这里进一步讨Z?NETc?以及他们在多U程~程中扮演的角色和怎么~程。它们是:

  System.Threading.ThreadPool c?/strong>

  System.Threading.Timer c?br />
  如果U程的数目ƈ不是很多,而且你想控制每个U程的细节诸如线E的优先U等,使用Thread是比较合适的;但是如果有大量的U程,考虑使用U程池应该更好一?它提供了高效的线E管理机制来处理多Q务?对于定期的执行Q务TimercL合适的;使用代表是异步方法调用的首选?br />
System.Threading.ThreadPool Class

  当你创徏应用E序?你应该认识到大部分时间你的线E在I闲的等待某些事件的发生(诸如按下一个键或侦听套节子的请?。毫无疑问的,你也会认是绝对的费资源?br />
  如果q里有很多的d需要完?每个d需要一个线E?你应该考虑使用U程池来更有效的理你的资源q且从中受益。线E池是执行的多个U程集合,它允怽d以线E自动创建和开始的d到队列里面去。用线E池使得你的pȝ可以优化U程在CPU使用时的旉片。但是要C在Q何特定的旉?每一个进E和每个U程池只有一个一个正在运行的U程。这个类使得你的U程l成的池可以被系l管?而你的主要_֊集中在工作流的逻辑而不是线E的理?br />
  当第一ơ实例化ThreadPoolcLU程池将被创建。它有一个默认的上限,x处理器最多可以有25?但是q个上限是可以改变的。这样得处理器不会闲置下来。如果其中一个线E等待某个事件的发生,U程池将初始化另外一个线Eƈ投入处理器工?U程池就是这样不停的创徏工作的线E和分配dl那些没有工作的在队列里的线E。唯一的限制是工作U程的数目不能超q最大允许的数目。每个线E将q行在默认的优先U和使用默认的属于多U程I间的堆栈大空间。一旦一工作Q务被加入队列,你是不能取消的?br />
  hU程池处理一个Q务或者工作项可以调用QueueUserWorkItemҎ。这个方法带一个WaitCallback代表cd的参?q个参数包装了你药完成的d。运行时自动为每一个的d创徏U程q且在Q务释放时释放U程?br />
  下面的代码说明了如何创徏U程池和怎样dd:

public void afunction(object o)

{

// do what ever the function is supposed to do.

}

//thread entry code

{

// create an instance of WaitCallback

WaitCallback myCallback = new WaitCallback (afunction);

//add this to the thread pool / queue a task

ThreadPool.QueueUserWorkItem (myCallback);

}


  你也可以通过调用ThreadPool.RegisterWaitForSingleObjectҎ来传递一个System.Threading.WaitHandle,当被通知或者时间超q了调用被System.Threading.WaitOrTimerCallback包装的方法?/p>

  U程池和Z事g的编E模式得线E池Ҏ册的WaitHandles的监控和对合适的WaitOrTimerCallback代表Ҏ的调用十分简?当WaitHandle被释放时)。这些做法其实很单。这里有一个线E不断的观测在线E池队列{待操作的状态。一旦等待操作完?一个线E将被执行与其对应的d。因?q个Ҏ随着出发触发事g的发生而增加一个线E?br />
  让我们看看怎么随事件添加一个线E到U程?其实很简单。我们只需要创Z个ManualResetEventcȝ事g和一个WaitOrTimerCallback的代?然后我们需要一个携带代表状态的对象,同时我们也要军_休息间隔和执行方式。我们将上面的都d到线E池,q且Ȁ发一个事?

public void afunction(object o)

{

// do what ever the function is supposed to do.

}


//object that will carry the status information

public class anObject

{

}

//thread entry code

{

//create an event object

ManualResetEvent aevent = new ManualResetEvent (false);


// create an instance of WaitOrTimerCallback

WaitOrTimerCallback thread_method = new WaitOrTimerCallback (afunction);


// create an instance of anObject

anObject myobj = new anObject();


// decide how thread will perform

int timeout_interval = 100; // timeout in milli-seconds.

bool onetime_exec = true;


//add all this to the thread pool.

ThreadPool. RegisterWaitForSingleObject (aevent, thread_method, myobj, timeout_interval, onetime_exec);


// raise the event

aevent.Set();

}


  在QueueUserWorkItem和RegisterWaitForSingleObjectҎ?U程池创Z一个后台的U程来回调。当U程池开始执行一个Q?两个Ҏ都将调用者的堆栈合ƈ到线E池的线E堆栈中。如果需要安全检查将耗费更多的时间和增加pȝ的负?因此可以通过使用它们对应的不安全的方法来避免安全查。就是ThreadPool.UnsafeRegisterWaitForSingleObject 和ThreadPool.UnsafeQueueUserWorkItem?br />
  你也可以对与{待操作无关的Q务排队?Timer-queue timers and registered wait operations也用线E池。它们的q回Ҏ也被攑օU程池排队?br />
  U程池是非常有用?被广泛的用于。NETq_上的套节子编E?{待操作注册,q程计时器和异步的I/O。对于小而短的Q?U程池提供的机制也是十分便利处于多线E的。线E池对于完成许多独立的Q务而且不需要逐个的设|线E属性是十分便利的。但?你也应该很清?有很多的情况是可以用其他的方法来替代U程池的。比如说你的计划d或给每个U程特定的属?或者你需要将U程攑օ单个U程的空?而线E池是将所有的U程攑օ一个多U程I间),抑或是一个特定的d是很冗长?q些情况你最好考虑清楚,安全的办法比用线E池应该是你的选择?br />

System.Threading.Timer Class

  Timercd于周期性的在分ȝU程执行d是非常有效的,它不能被l承?br />
  q个cd其用来开发控制台应用E序,因ؓSystem.Windows.Forms.Time是不可用的。比如同来备份文件和查数据库的一致性?/p>

  当创建Timer对象?你药估计在第一个代理调用之前等待的旉和后来的每次成功调用之间的时间。一个定时调用发生在Ҏ的应得时间过?q且在后来周期性的调用q个Ҏ。你可以适应Timer的ChangeҎ来改变这些设|的值或者Timer失效。当定时器Timer不再使用?你应该调用DisposeҎ来释攑օ资源?br />
  TimerCallback代表负责指定与Timer对象相关联的Ҏ(是要周期执行的d)和状态。它在方法应得的旉q去之后调用一ơƈ且周期性的调用q个Ҏ直到调用了DisposeҎ释放了Timer的所有资源。系l自动分配分ȝU程?br />
  让我们来看一D代码看看事如何创徏Timer对象和用它的。我们首先要创徏一个TimerCallback代理,在后面的Ҏ中要使用到的。如果需?下一步我们要创徏一个状态对?它拥有与被代理调用的Ҏ相关联的特定信息。ؓ了ɘq些单一?我们传递一个空参数。我们将实例化一个Timer对象,然后再用ChangeҎ改变Timer的设|?最后调用DisposeҎ释放资源?br />

// class that will be called by the Timer

public class WorkonTimerReq

{

public void aTimerCallMethod()

{

// does some work

}

}


//timer creation block

{

//instantiating the class that gets called by the Timer.

WorkonTimerReq anObj = new WorkonTimerReq () ;


// callback delegate

TimerCallback tcallback = new TimerCallback(anObj. aTimerCallMethod) ;


// define the dueTime and period

long dTime = 20 ; // wait before the first tick (in ms)

long pTime = 150 ; // timer during subsequent invocations (in ms)


// instantiate the Timer object

Timer atimer = new Timer(tcallback, null, dTime, pTime) ;


// do some thing with the timer object

...

//change the dueTime and period of the Timer

dTime=100;

pTime=300;

atimer.Change(dTime, pTime) ;

// do some thing

...

atimer.Dispose() ;

...

}



异步~程

  q部分内容如果要讲清楚本来就是很大的一部分,在这?我不打算详细讨论q个东西,我们只是需要直到它是什?因ؓ多线E编E如果忽律异步的多线E编E显然是不应该的。异步的多线E编E是你的E序可能会用到的另外一U多U程~程Ҏ?br />
  在前面的文章我们׃很大的篇q来介绍U程的同步和怎么实现U程的同?但是它有一个固有的致命的缺?你或许注意到了这一炏V那是每个U程必须作同步调?也就是等到其他的功能完成,否则阻塞。当?某些情况?对于那些逻辑上相互依赖的d来说是够的。异步编E允许更加复杂的灉|性。一个线E可以作异步调用,不需要等待其他的东西。你可以使用q些U程作Q何的d,U程负责获取l果推进q行。这l予了那些需要管理数目巨大的h而且负担不vh{待代h的企业的系l更好的可׾~性?br />
  .NETq_提供了一致的异步~程机制用于ASP.NET,I/O,Web Services,Networking,Message{?br />

后记

  ׃学习的时候很难找C文这斚w的资料,因此我就只好学习英文的资料,׃水^不高Q翻译的时候可能难免曲解原文的意思,希望大家能够指出Q同时希望这些东西能够给大家在学习这斚w知识l予一定的参考和帮助Q那怕是一点点Q就很欣C?/p>

醒目西西 2006-12-07 15:05 发表评论
]]>
c#.net多线E编E教?2):Threadc?http://www.shnenglu.com/xingmuxixi/articles/16094.html醒目西西醒目西西Thu, 07 Dec 2006 07:03:00 GMThttp://www.shnenglu.com/xingmuxixi/articles/16094.htmlhttp://www.shnenglu.com/xingmuxixi/comments/16094.htmlhttp://www.shnenglu.com/xingmuxixi/articles/16094.html#Feedback0http://www.shnenglu.com/xingmuxixi/comments/commentRss/16094.htmlhttp://www.shnenglu.com/xingmuxixi/services/trackbacks/16094.htmlq章向大家介绍.NET中的U程API,怎么LC#创徏U程,启动和停止线E?讄优先U和状?

  ?NET中编写的E序被自动的分配一个线E?让我们来看看用C#~程语言创徏U程q且l箋学习U程的知识。我们都知道.NET的运行时环境的主U程由Main ()Ҏ来启动应用程序,而且.NET的编译语a有自动的垃圾攉功能,q个垃圾攉发生在另外一个线E里?所有的q些都是后台发生?让我们无法感觉到发生了什么事?在这里默认的是只有一个线E来完成所有的E序dQ但是正如我们在W一文章讨的一P有可能我们根据需要自己添加更多的U程让程序更好的协调工作。比如说我们的例子中Q一个有用户输入的同旉要绘制图形或者完成大量的q算的程序,我们必须得增加一个线E,让用L输入能够得到及时的响应,因ؓ输入Ҏ间和响应的要求是紧迫的,而另外一个线E负责图形绘制或者大量的q算?br />
  .NET 基础cd的System.Threading命名I间提供了大量的cd接口支持多线E。这个命名空间有很多的类Q我们将在这里着重讨论Threadq个cR?br />
  System.Threading.ThreadcL创徏q控制线E,讄其优先q获取其状态最为常用的cR他有很多的ҎQ在q里我们就比较常用和重要的Ҏ做一下介l:

  Thread.StartQ)Q启动线E的执行Q?br />
  Thread.SuspendQ)Q挂LE,或者如果线E已挂vQ则不v作用Q?br />
  Thread.ResumeQ)Ql已挂v的线E;

  Thread.InterruptQ)Q中止处?Wait或者Sleep或者Join U程状态的U程Q?br />
  Thread.JoinQ)Q阻塞调用线E,直到某个U程l止时ؓ?br />
  Thread.SleepQ)Q将当前U程d指定的毫U数Q?br />
  Thread.AbortQ)Q以开始终止此U程的过E。如果线E已l在l止Q则不能通过Thread.StartQ)来启动线E?br />
  通过调用Thread.SleepQThread.Suspend或者Thread.Join可以暂停/dU程。调用Sleep()和Suspend()Ҏ意味着U程不再得到CPU旉。这两种暂停U程的方法是有区别的QSleep()使得U程立即停止执行Q但是在调用Suspend()Ҏ之前Q公paq行时必d达一个安全点。一个线E不能对另外一个线E调用Sleep()ҎQ但是可以调用Suspend()Ҏ使得另外一个线E暂停执行。对已经挂v的线E调用Thread.ResumeQ)Ҏ会其l执行。不用多次Suspend()Ҏ来阻塞一个线E,只需一ơ调用Resume()Ҏ可以得线El执行。已l终止的和还没有开始执行的U程都不能用挂赗Thread.SleepQint xQɾU程dx毫秒。只有当该线E是被其他的U程通过调用Thread.InterruptQ)或者Thread.AbortQ)ҎQ才能被唤醒?

  如果对处于阻塞状态的U程调用Thread.InterruptQ)ҎɾU程状态改变,但是会抛出ThreadInterupptedException异常Q你可以捕获q个异常q且做出处理Q也可以忽略q个异常而让q行时终止线E。在一定的{待旉之内QThread.InterruptQ)和Thread.AbortQ)都可以立卛_醒一个线E?br />
  下面我们说明如何从一个线E中止另外一个线E。在q种情况下,我们可以通过使用Thread.AbortQ)Ҏ来永久销毁一个线E,而且抛出ThreadAbortException异常。ɾl结的线E可以捕获到异常但是很难控制恢复Q仅有的办法是调用Thread.ResetAbortQ)来取消刚才的调用Q而且只有当这个异常是׃被调用线E引L异常。因此,AU程可以正确的用Thread.AbortQ)Ҏ作用于BU程Q但是BU程却不能调用Thread.ResetAbortQ)来取消Thread.AbortQ)操作?/p>

  Thread.AbortQ)Ҏ使得pȝ悄悄的销毁了U程而且不通知用户。一旦实施Thread.AbortQ)操作Q该U程不能被重新启动。调用了q个Ҏq不是意味着U程立即销毁,因此Z定U程是否被销毁,我们可以调用Thread.JoinQ)来确定其销毁,Thread.JoinQ)是一个阻塞调用,直到U程的确是终止了才返回。但是有可能一个线E调用Thread.InterruptQ)Ҏ来中止另外一个线E,而这个线E正在等待Thread.JoinQ)调用的返回?/p>

  可能的不要用Suspend()Ҏ来挂起阻塞线E,因ؓq样很容易造成死锁。假设你挂v了一个线E,而这个线E的资源是其他线E所需要的Q会发生什么后果。因此,我们可能的l重要性不同的U程以不同的优先U,用Thread.PriorityQ)Ҏ来代替用Thread.SuspendQ)Ҏ?br />
  ThreadcL很多的属性,q些重要的属性是我们多线E编E必d掌握的?br />
  Thread.IsAlive属性:获取一个|该值指C当前线E的执行状态。如果此U程已启动ƈ且尚未正常终止或中止Q则?trueQ否则ؓ false?br />
  Thread.Name 属性:获取或设|线E的名称?br />
  Thread.Priority 属性:获取或设|一个|该值指C线E的调度优先U?br />  Thread.ThreadState 属性:获取一个|该值包含当前线E的状态?br />  在下面的例子中,我们看看怎么讄q些属性,在随后的例子中我们将详细的讨些属性?br />  创徏一个线E,首先得实例化一个Threadc,在类得构造函C调用ThreadStart委派。这个委z֌含了U程从哪里开始执行。当U程启动后,Start()Ҏ启动一个新的线E。下面是例子E序?br />

using System;
using System.Threading ;
namespace LearnThreads
{
class Thread_App
{
public static void First_Thread()
{
 Console.WriteLine("First thread created");
 Thread current_thread = Thread.CurrentThread;
 string thread_details = "Thread Name: " + current_thread.Name + "\r\nThread State: " + current_thread.ThreadState.ToString()+"\r\n Thread Priority level:"+current_thread.Priority.ToString();
 Console.WriteLine("The details of the thread are :"+ thread_details);
 Console.WriteLine ("first thread terminated");
}

public static void Main()
{
 ThreadStart thr_start_func = new ThreadStart (First_Thread);
 Console.WriteLine ("Creating the first thread ");
 Thread fThread = new Thread (thr_start_func);
 fThread.Name = "first_thread";
 fThread.Start (); //starting the thread
}
}
}


  在这个例子中Q创Z一个fThread的线E对象,q个U程负责执行First_Thread()Ҏ里面的Q务。当Thread的Start() Ҏ被调用时包含First_Thread()的地址ThreadStart的代理将被执行?br />
Thread状?/strong>
  System.Threading.Thread.ThreadState属性定义了执行时线E的状态。线E从创徏到线E终止,它一定处于其中某一个状态。当U程被创建时Q它处在Unstarted状态,ThreadcȝStart() ҎɾU程状态变为Running状态,U程一直处于这L状态,除非我们调用了相应的Ҏ使其挂v、阻塞、销毁或者自然终止。如果线E被挂vQ它处于Suspended状态,除非我们调用resumeQ)Ҏ使其重新执行Q这时候线E将重新变ؓRunning状态。一旦线E被销毁或者终止,U程处于Stopped状态。处于这个状态的U程不复存在,正如U程开始启动,U程不可能回到Unstarted状态。线E还有一个Background状态,它表明线E运行在前台q是后台。在一个确定的旉Q线E可能处于多个状态。据例子来说Q一个线E被调用了Sleep而处于阻塞,而接着另外一个线E调用AbortҎ于这个阻塞的U程Q这时候线E将同时处于WaitSleepJoin和AbortRequested状态。一旦线E响应{为Sled或者中止,当销毁时会抛出ThreadAbortException异常?br />
U程优先U?/strong>
  System.Threading.Thread.Priority枚D了线E的优先U别Q从而决定了U程能够得到多少CPU旉。高优先U的U程通常会比一般优先的线E得到更多的CPU旉Q如果不止一个高优先U的U程Q操作系l将在这些线E之间@环分配CPU旉。低优先U的U程得到的CPU旉相对较少Q当q里没有高优先的线E,操作pȝ挑选下一个低优先U?的线E执行。一旦低优先U的U程在执行时遇到了高优先U的U程Q它让出CPUl高优先U的U程。新创徏的线E优先Z般优先Q我们可以设|线E的优先U别的|如下面所C:

  Highest
  AboveNormal
  Normal
  BelowNormal
  Lowest


l论Q在q一部分Q我们讨ZU程的创ZU程的优先。System.Threading命名I间q包含了U程锁定、线E同步何通讯、多U程理cM及死锁解决等{高U特性,在后面的部分我们l讨些内宏V?/p>

醒目西西 2006-12-07 15:03 发表评论
]]>
使用 .NET Remoting 实现q行计算 [转] http://www.shnenglu.com/xingmuxixi/articles/16092.html醒目西西醒目西西Thu, 07 Dec 2006 07:02:00 GMThttp://www.shnenglu.com/xingmuxixi/articles/16092.htmlhttp://www.shnenglu.com/xingmuxixi/comments/16092.htmlhttp://www.shnenglu.com/xingmuxixi/articles/16092.html#Feedback0http://www.shnenglu.com/xingmuxixi/comments/commentRss/16092.htmlhttp://www.shnenglu.com/xingmuxixi/services/trackbacks/16092.html.NET Remoting 使您可以跨多台计机Lq行分布计算Q只需完成非常的~程工作。在本文中,Eric Bergman-Terrell 创徏了一个名为 Digits of Pi 的应用程序,它用ƈ行的多台计算Z不可思议的精度计 p 倹{他设法在?2 时内完成了 10,000 位数的计,却只使用了相当少的计资源。这比用一台计机单独完成计算快了 300Q?br />
单击下蝲文g下蝲CZ应用E序源代码后Q打开 Everything.sln 解决Ҏ。此解决Ҏ包含q行“Digits of Pi”应用程序所需的三个项目(Client、Server 和 ServerLoaderQ。还包含一个名为 SimpleClient 的项目,我们E后再讨论它。加qEverything.sln 之后Q请选择 BuildQ编译)| Batch Build...Q批~译...Q。单击 Select AllQ全部选定Q按钮,然后单击 BuildQ编译)。编译所有内容后Q请在本地计机以及您的 LAN 中的q程计算Z安装该Y件?br />
在本地计机上,创徏一个文件夹q将以下文g复制到其中:

Server\bin\Release\Plouffe_Bellard.dll
Client\bin\Release\DigitsOfPi.exe

在每个远E计机和本地计机上,创徏一个文件夹q将以下文g复制到其中:

Server\bin\Release\Plouffe_Bellard.dll
ServerLoader\bin\Release\ServerLoader.exe
ServerLoader\ServerLoader.exe.config

然后q行 ServerLoader.exe E序。当Ӟq行 ServerLoader 和 Digits of Pi E序之前Q需要在每台计算Z安装 .NET Framework?br />
在所有远E计机和本地计机上运行 ServerLoader E序后,误行 Digits of Pi E序。单击 Configure...Q配|?..Q(参见图?Q,d本地计算机名和远E计机名。如果不定某台计算机的名称Q请查看 ServerLoader E序Q它在表中显C其计算机名。如果您很幸q地拥有一个多 CPU pȝQ您只需为所有 CPU 输入一ơ计机名。只需在计机名后键入 @ W号和一个编受例如,如果您拥有一个名为“Brainiac”的双 CPU pȝQ则键入以下计算机名Q“Brainiac@1”和“Brainiac@2”。不必ؓ多个 CPU pȝ输入多个计算机名Q但是这样做可以保所有计机的 CPU 都用于计 p 倹{输入所有计机名后Q单击 OKQ确定)?br />
然后指定要计的位数Q参见图 2Qƈ单击 CalculateQ计)。请从较的位数开始,p 值小数点后面的位数越多,E序所需的时间就长?br />
图? 昄了 Digits of Pi E序如何在本地计机和远E计机中分配工作量Q它使用 TCP/IP 端口 9000 发送请求ƈ接收l果。接下来Q我们将详细探讨 Remoting、Plouffe_Bellard 服务器对象、ServerLoader E序、SimpleClient E序和 Digits of Pi E序?br />
Remoting 基础
.NET Remoting 使对象可以与其他对象通信Q无论它们运行在同一台计机上还是运行在q程计算Z?NET Remoting 与 Web 服务非常cMQ但是?NET Remoting 技术更适于 Digits of Pi q种完全以?NET ~程语言~写的应用程序,q且只能在运行?NET Framework 的计机上运行。请参阅本文末尾“其他资源”中的“ASP.NET Web Services or .NET Remoting: How to Choose”,对两U技术进行比较。?br />
您可以通过以下步骤使用 .NET Remoting 讉Kq程对象Q?br />
创徏从 System.MarshalByRefObject l承的?NET 服务器对象?DLL)。该服务器对象将在远E计机和本地计机上运行。?br />创徏通过调用 RemotingConfiguration.Configure 加蝲服务器对象的服务器加载器E序。服务器加蝲器程序也在q程计算机和本地计算Zq行。?br />创徏使用 Activator.GetObject 讉K服务器对象的客户端程序。您需要添加对服务器对象的引用以编译此E序。此客户端程序只在本地计机上运行。?br />服务器对?br />服务器对象将计算指定的九位 p 倹{它被命名ؓ Plouffe_BellardQ因为它使用 Fabrice Bellard 的增强的 Simon Plouffe 法。虽然存在更快的法Q但 Plouffe-Bellard 法非常单(于 300 行源代码Q,它用少量的内存Qƈ且由于九位数字可以单独计,因此更适于q行执行。Plouffe_Bellard.CalculatePiDigits Ҏ计在指定位置开始的九位 p 倹{例如,CalculatePiDigits(1) 从第一位开始返回九位数字:141592653。CalculatePiDigits(10) 从第十位开始返回九位数字,依此cL。?br />
ServerLoader
ServerLoader E序加载服务器对象Q指定通过 LAN 讉K服务器对象的协议和端口,侦听来自客户端程序的传入调用Q处理调用ƈq回l果。特别值得注意的是Q所有这些只需一行代码便可完成,只需通过使用配置文g的\径调用 RemotingConfiguration.Configure Ҏ。ServerLoader E序加载名为 ServerLoader.exe.config 的配|文Ӟ参见表?Q。此配置文g指定以 SingleCall 模式加蝲服务器对象,x个传入调用都由服务器对象的一个新实例处理。如果服务器对象以 Singleton 模式加蝲Q每个传入调用都由同一个实例处理。类型属性指定服务器对象的完整类型名Uͼ包括 PB 命名I间Q及其程序集的名U。objectUri 属性指定对象的l一资源标识W?URI) 的端炏V?lt;channel> 元素指定使用 TCP 协议Q端口?000 讉K服务器对象。?br />
表?QServerLoader.exe.config?br />
<configuration> 
  <system.runtime.remoting>  
    <application name = "ServerLoader">  
      <service> 
        <wellknown 
          mode="SingleCall" 
          type="PB.Plouffe_Bellard,Plouffe_Bellard"
          objectUri="Plouffe_Bellard"/> 
      </service> 
      <channels> 
        <channel ref="tcp server" port="9000"/>
      </channels> 
    </application> 
  </system.runtime.remoting>
</configuration> 

SimpleClient
我创Z一个名为 SimpleClient 的程序,以说明客LE序讉Kq程计算Z的服务器对象是多么容易。要q行 SimpleClientQ首先在q程计算Zq行 ServerLoaderQ然后在本地计算Zq行 SimpleClient.exe E序。在 Remote MachineQ远E计机Q文本框中输入远E计机的名Uͼ然后单击 CalculateQ计)按钮开始计第一个九位 p 倹{SimpleClient 的 CalculateButton_Click Ҏ包含客户端访问远E服务器所需的所有代码(参见表?Q。可以用由q程计算机名、协议?TCP) 和端口号 (9000) l成的 URL 讉Kq程服务器。例如,要访问我的“Pentium 200”计机Q则 URL 为 tcp://Pentium 200:9000/ServerLoader/Plouffe_Bellard。创建 URL 后,用服务器的类型?Plouffe_Bellard) 和 URL 调用 Activator.GetObject。然后,q回的D转换为 Plouffe_Bellard 对象以备使用。调用其 CalculatePiDigits ҎӞh被发送到q程计算Z的 ServerLoader。然后,服务器对象计小C。最后,在一个文本框中显C回客LE序的结果。?br />
表?Q用于访问远E服务器的 SimpleClient 代码?br />
private void CalculateButton_Click(object sender, 
                              System.EventArgs e)
{
  Cursor.Current = Cursors.WaitCursor;

  Plouffe_Bellard PiCalculator = null;

  String MachineName = RemoteMachineTextBox.Text;

  try
  {
    int port = 9000;

    String URL = "tcp://" + MachineName + ":" + 
       port + "/ServerLoader/Plouffe_Bellard";
    PiCalculator = (Plouffe_Bellard) 
       Activator.GetObject(typeof(Plouffe_Bellard), URL);
    ResultsTextBox.Text = "3." + 
       PiCalculator.CalculatePiDigits(1);
  }
  catch(Exception)
  {
    MessageBox.Show(
       "需要在计算机? +
       MachineName, "Simple Client 上运行 ServerLoader.exe", 
       MessageBoxButtons.OK, MessageBoxIcon.Error);
  }

  Cursor.Current = Cursors.Arrow;
}

Digits of Pi 客户?br />Digits of Pi 客户端程序比 SimpleClient 更复杂。SimpleClient 仅通过讉Kq程计算Z的服务器对象来计前九位 p 倹{而 Digits of Pi 则同时用 ConfigureQ配|)对话框中指定的远E计机和本地计机Q如图? 所C)q行计算用户指定的小C。服务器对象在单独的U程中访问,以便在可能需要很长时间的计算q程中保持 Digits of Pi GUI 对用h作的响应性。?br />
Digits of Pi 使用数组作业分Z位数据块Q将工作量分配到所有可用的计算Z。用户单击 CalculateQ计)按钮后,创建 SolutionArrayQ参见图 4Q。SolutionArray 计算的每l九位 p 值分配一个 SolutionItem 元素。服务器对象计算 m_Digit 字段指定的九位数l后Q数位将存储在 m_Results 成员中。m_MachineName 成员包含q行服务器的计算机的名称。存储计机名是Z使 Digits of Pi 能够昄每台计算的数LQ参见图 2Q?br />
Z服务器对象ƈ行计,Digits of Pi ؓ每个服务器对象创Z个线Eƈ启动U程计算。然后,必须{待所有线E完成计后才能昄最l结果。WaitHandle 对于{待多个U程很有用。Digits of Pi ؓ每个U程使用一个 WaitHandleQ以{待所有线E完成计?br />
调用 CalculationThread.CalculateQ参见表 3Q以便ؓ每个服务器对象创Z个线E。该操作启动线E运行,然后q回一个 AutoResetEventQ从 WaitHandle 衍生而来Q。每个线E的 AutoResetEvent 都存储在一个数l中Q然后数l被传递给 WaitHandle.WaitAll。完成线E计后Q将对其 AutoResetEvent 调用 Set Ҏ。最后一个线E调用 Set Ҏ后,返回 WaitAll 调用Qƈ昄 p 的倹{?br />
表?QCalculationThread?br />
public static WaitHandle Calculate(
SolutionArray solutionArray, String machineName)
{
  CalculationThread calculationThread = new 
    CalculationThread(solutionArray, machineName);
  Thread thread = new Thread(new 
    ThreadStart(calculationThread.Calculate));
  thread.Start();
  return calculationThread.calculationDone;
}

每个U程都用相同的法Q如果有更多的工作要处理Q线E将夺取下一个 SolutionItemQ在 SolutionItem 中存储服务器对象的计机名,计算指定的九位小敎ͼq将l果存储在 SolutionItem 中。此q程一直运行,直到所有 SolutionItem 中都填充了结果。有兌l信息,请参见表 4?br />
表?QCalculationThread.Calculate?br />
public void Calculate()
{
  Plouffe_Bellard PiCalculator = 
    RemotePiCalculator.GetPiCalculator(
      GetRealMachineName(machineName));

  if (PiCalculator != null)
  {
    SolutionItem Item = null;
    bool Abort;

    do
    {
      Abort = solutionArray.Abort;

      if (!Abort)
      {
        Item = solutionArray.GetNextItem();

        if (Item != null)
        {
          Item.MachineName = machineName;

          try
          {
            Item.Results = 
           PiCalculator.CalculatePiDigits(Item.Digit);
          }
          catch (Exception e)
          {
            Abort = true;
            MessageBox.Show(
              "无法讉KL上的q程对象 " +
              machineName + Environment.NewLine + 
              Environment.NewLine + "Message:  " + 
              e.Message, Globals.ProgramName, 
              MessageBoxButtons.OK, 
              MessageBoxIcon.Error);
          }

          UpdateStatisticsDelegate USD = new 
            UpdateStatisticsDelegate(
              MF.UpdateStatistics);

          MF.Invoke(USD, new Object[] {} ;
        }
      }
    } while (Item != null && !Abort);

    calculationDone.Set();
  }
}

下面是逐步的说明:

GetRealMachineName 从多 CPU 计算机名中删除 @1 模式。例如,GetRealMachineName("Brainiac@1" q回 "Brainiac"。有兛_ CPU 计算机名的解释,请参见图 1 对话框中的文本。?br />知道正确的计机名后Q将其传递给 RemotePiCalculator.GetPiCalculatorQ这h可以通过 PiCalculator 变量讉K该计机上的服务器对象。?br />如果用户单击了 CancelQ取消)按钮Q将讄 Abort 属性。如果 Abort 属性ؓ trueQ线E将停止计算。?br />对 MF.Invoke 的调用ɾU程可以安全地更斊WListView 中的l计数据Q参见图 2Q,即该 ListView 是由另一个线E创建的。在 32 位 Windows ~程中,l不允许在创建某个控件的U程之外处理该控件。?br />完成循环Q即计算完指定的所有 p 位数或者用户单击 Cancel [取消] 按钮Q后Q将调用U程的 AutoResetEvent 的 Set 函数。?br />当每个线E都调用其 AutoResetEvent 的 Set 函数后,返回对 WaitHandle.WaitAll 的调用ƈ昄l果。?br />U程同步
如果 Digits of Pi 的代码由多个U程同时讉KQ可能会有多个地方出现错误。例如,如果两个U程同时调用 SolutionArray.GetNextItemQ可能会q回相同的内宏V这是在 GetNextItem Ҏ中设| [MethodImpl(MethodImplOptions.Synchronized)] 属性的原因Q该属性可以确保一ơ只有一个线E调用该Ҏ。如果方法的每一行代码都不应由多个线E同时访问,则Ҏ同步是一个很好的{略。?br />
׃ MainForm.Calculate Ҏ只有一行代码不能同时被多个U程讉KQ因此它在该行代码之前调用 Monitor.EnterQƈ在其后调用 Monitor.Exit。如果该行代码已在其他线E上q行QMonitor.Enter 被L。如果整个函数已实现同步Q那么只保护需要防止多个线E访问的代码行可以提高性能?br />
从 System.Windows.Forms.Control 衍生的对象(例如 Button、TextBoxe、RichTextBoxe、Label、ListBoxe、ListView {等Q只应由创徏它们的线E处理。要从非创徏U程中安全处理 Control 衍生对象Q请首先处理代码放入一个方法,然后Ҏ声明一个代理:

delegate void SetResultsTextDelegate(String Text);

private void SetResultsText(String Text)
{
  ResultsRichTextBox.Text = Text;
}

然后使用 Form.Invoke 间接调用该方法:

SetResultsTextDelegate SRTD = new 
   SetResultsTextDelegate(SetResultsText);

Invoke(SRTD, new object[] { "" } ;

Invoke Ҏ从创徏它的U程中调用该ҎQ它使用的参C对象数组中的元素相对应?br />

.NET Remoting 是一U在q程Q和本地Q计机上执行代码的单而有效的机制。只需代码封装到 .NET 对象中,~写加蝲该对象ƈ侦听h的程序,然后在客LE序中调用 Activator.GetObject。如果您的 LAN 中有一些闲|的计算机,可以利用它们L地解军_ƈ行问题。只需C要用正的U程同步机制Q以防止U程之间发生冲突。?br />
下蝲 TERRELL.ZIP

其他资源
“ASP.NET Web 服务q是 .NET RemotingQ如何选择 ?::URL::http://www.microsoft.com/china/msdn/library/dnbda/html/bdadotnetarch16.asp)  一文很有用Q它对?NET Web Service 和?NET Remoting q行了比较。?br />Fabrice Bellard's Pi Page (::URL::http://fabrice.bellard.free.fr/pi/)  提供了一些用于计 p 值的有用公式和源代码Q包括 Digits of Pi E序中用的法的 C 语言源代码。?br />有关q程讉KE序的源代码Q请讉K www.personalmicrocosms.com/html/ra.html。此E序使用 .NET Remoting 昄q程计算机的桌面Qƈ使用本地计算机的键盘和鼠标运行远E计机。?br />有关数学化方面的内容Q请参阅 Petr Beckmann 著的《History of Pi》(St. Martin's Press 1971 q出版)Q这是一本相当不错的书,因ؓ p 的历史就是数学历史的微观反映。Beckmann 的书늛了 p 的数学历史以及政d双Ӏ?br />Ingo Rammer 的《Advanced .NET Remoting》(Apress 2002 q出版)是有ꐠRemoting 的权威指南。此书看h更适合从头到尾的详l阅诅R我倒是希望此书能够适合我的“随便翻Z的阅读习惯。?br />有关 Hardcore Visual Studio .NET 和 Pinnacle Publishing 的详l信息,误问它们的 Web 站点 ::URL::http://www.pinpub.com/?/a>

注意Q这不是 Microsoft Corporation 的 Web 站点。Microsoft 对该站点的内容不承担责Q?br />
本文转蝲自?003 qb? 月䆾的 Hardcore Visual Studio .NET。版权所有?003 Pinnacle Publishing, Inc.Q除非另行说明)。保留所有权利。Hardcore Visual Studio .NET 是 Pinnacle Publishing, Inc. 独立发行的刊物。未l Pinnacle Publishing, Inc. 事先同意Q不得以M形式使用或复制本文的M部分Q评论文章中的简短引用除外)。如需与 Pinnacle Publishing, Inc.联系Q请致电 1-800-788-1900?br />

醒目西西 2006-12-07 15:02 发表评论
]]>
[C#学习]在多U程中如何调用Winformhttp://www.shnenglu.com/xingmuxixi/articles/16086.html醒目西西醒目西西Thu, 07 Dec 2006 06:37:00 GMThttp://www.shnenglu.com/xingmuxixi/articles/16086.htmlhttp://www.shnenglu.com/xingmuxixi/comments/16086.htmlhttp://www.shnenglu.com/xingmuxixi/articles/16086.html#Feedback0http://www.shnenglu.com/xingmuxixi/comments/commentRss/16086.htmlhttp://www.shnenglu.com/xingmuxixi/services/trackbacks/16086.html
  我的WinFormE序中有一个用于更CH口的工作线E(worker threadQ,但文档中却提C我不能在多U程中调用这个formQؓ什么?Q,而事实上我在调用时程序常怼崩掉。请问如何从多线E中调用form中的Ҏ呢?

  解答Q?br />
  每一个从ControlcMz出来的WinFormc(包括Controlc)都是依靠底层Windows消息和一个消息܇循环Qmessage pump loopQ来执行的。消息@环都必须有一个相对应的线E,因ؓ发送到一个window的消息实际上只会被发送到创徏该window的线E中厅R其l果是,即提供了同步(synchronizationQ,你也无法从多U程中调用这些处理消息的Ҏ。大多数plumbing是掩藏v来的Q因为WinForm是用代理QdelegateQ将消息l定C件处理方法中的。WinFormWindows消息转换Z个基于代理的事gQ但你还是必L意,׃最初消息@环的~故Q只有创form的线E才能调用其事g处理Ҏ。如果你在你自己的线E中调用q些ҎQ则它们会在该线E中处理事gQ而不是在指定的线E中q行处理。你可以从Q何线E中调用M不属于消息处理的Ҏ?br />
  Controlc(及其zc)实现了一个定义在System.ComponentModel命名I间下的接口 -- ISynchronizeInvokeQƈ以此来处理多U程中调用消息处理方法的问题Q?br />
public interface ISynchronizeInvoke
{
 object Invoke(Delegate method,object[] args);
 IAsyncResult BeginInvoke(Delegate method,object[] args);
 object EndInvoke(IAsyncResult result);
 bool InvokeRequired {get;}
}

  ISynchronizeInvoke提供了一个普通的标准机制用于在其他线E的对象中进行方法调用。例如,如果一个对象实CISynchronizeInvokeQ那么在U程T1上的客户端可以在该对象中调用ISynchronizeInvoke的Invoke()Ҏ。Invoke()Ҏ的实CdQblockQ该U程的调用,它将调用打包发送(marshalQ到 T2Qƈ在T2中执行调用,再将q回值发送会T1Q然后返回到T1的客L。Invoke()Ҏ以一个代理来定位该方法在T2中的调用Qƈ以一个普通的对象数组做ؓ其参数?br />
  调用者还可以查InvokeRequired属性,因ؓ你既可以在同一U程中调用ISynchronizeInvoke也可以将它重新定位(redirectQ到其他U程中去。如果InvokeRequired的返回值是false的话Q则调用者可以直接调用该对象的方法?br />
  比如Q假设你惌从另一个线E中调用某个form中的CloseҎQ那么你可以使用预先定义好的的MethodInvoker代理Qƈ调用InvokeҎ:

Form form;
/* obtain a reference to the form,
then: */
ISynchronizeInvoke synchronizer;
synchronizer = form;

if(synchronizer.InvokeRequired)
{
MethodInvoker invoker = new
MethodInvoker(form.Close);
synchronizer.Invoke(invoker,null);
}
else
form.Close();

  ISynchronizeInvoke不仅仅用于WinForm中。例如,一个CalculatorcL供了两个数字相加的Add()ҎQ它是通过ISynchronizeInvoke来实现的。用户必ȝ定ISynchronizeInvoke.Invoke()Ҏ的调用是执行在正的U程中的?br />
  C# 在正的U程中写入调?br />
  列表A. CalculatorcȝAdd()Ҏ用于两个数字相加。如果用L接调用Add()ҎQ它会在该用LU程中执行调用,而用户可以通过ISynchronizeInvoke.Invoke()调用写入正的U程中?

  列表A:

public class Calculator : ISynchronizeInvoke
{
 public int Add(int arg1,int arg2)
 { 
  int threadID = Thread.CurrentThread.GetHashCode();
  Trace.WriteLine( "Calculator thread ID is " + threadID.ToString());
  return arg1 + arg2;
 }
 //ISynchronizeInvoke implementation
 public object Invoke(Delegate method,object[] args)
 {
  public IAsyncResult BeginInvoke(Delegate method,object[] args)
  {
   public object EndInvoke(IAsyncResult result)
   {
    public bool InvokeRequired
    {
    }
   }
   //Client-side code
   public delegate int AddDelegate(int arg1,int arg2);

    int threadID = Thread.CurrentThread.GetHashCode();
    Trace.WriteLine("Client thread ID is " + threadID.ToString());

    Calculator calc;
    /* Some code to initialize calc */

    AddDelegate addDelegate = new AddDelegate(calc.Add);

    object[] arr = new object[2];
    arr[0] = 3;
    arr[1] = 4;

    int sum = 0;
    sum = (int) calc.Invoke(addDelegate,arr);
    Debug.Assert(sum ==7);

    /* Possible output:
    Calculator thread ID is 29
    Client thread ID is 30
    */

  或许你ƈ不想q行同步调用Q因为它被打包发送到另一个线E中M。你可以通过BeginInvoke()和EndInvoke()Ҏ来实现它。你可以依照通用?NET非同步编E模式(asynchronous programming modelQ来使用q些ҎQ用BeginInvoke()来发送调用,用EndInvoke()来实现等待或用于在完成时q行提示以及攉q回l果?br />
  q值得一提的是ISynchronizeInvokeҎq安全cd?cd不符会导致在执行时被抛出异常Q而不是编译错误。所以在使用ISynchronizeInvoke时要格外注意Q因为编辑器无法查出执行错误?br />
  实现ISynchronizeInvoke要求你用一个代理来在后期绑定(late bindingQ中动态地调用Ҏ。每一U代理类型均提供DynamicInvoke()ҎQ?public object DynamicInvoke(object[]
args);

  理论上来_你必d一个方法代理放C个需要提供对象运行的真实的线E中去,qInvoke() 和BeginInvoke()Ҏ中的代理中调用DynamicInvoke()Ҏ。ISynchronizeInvoke的实现是一个非同一般的~程技巧,本文附带的源文g中包含了一个名为Synchronizer的帮助类Qhelper classQ和一个测试程序,q个试E序是用来论证列表A中的CalculatorcL如何用SynchronizercL实现ISynchronizeInvoke的。Synchronizer是ISynchronizeInvoke的一个普通实玎ͼ你可以用它的派生类或者将其本w作Z个对象来使用QƈISynchronizeInvoke实现指派l它?

  用来实现Synchronizer的一个重要元素是使用一个名为WorkerThread的嵌套类Qnested classQ。WorkerThread中有一个工作项目(work itemQ查询。WorkItemcM包含Ҏ代理和参数。Invoke()和BeginInvoke()用来一个工作项目实例加入到查询里。WorkerThread新徏一?NET workerU程Q它负责监测工作目的查询Q务。查询到目之后Qworker会读取它们,然后调用DynamicInvoke()Ҏ?/p>

醒目西西 2006-12-07 14:37 发表评论
]]>
þþƷר| ҹƷþӰԺ| 鶹AV뾫Ʒþ| þþƷAVӰԺ| 99þۺϹƷ| Ʒѿþþ| ɫۺϾþþþ| ۺҹҹþ| ƷþòҰ| պӰԺþ| þþƷ91þۺ鶹 | þþþAVƬ| 91Ʒþþþþù۲| þþWWWëƬ| þ޾ƷƷ| ĻhdþþƷ| þAV| þ̳| þùƷ-Ʒ| AVþþƷ| þþƷѹۿ97| þ91Ʒ91þ鶹| þþù׮| ˾þô߽ۺ5g| þù| 99þùۺϾƷԭ| ۺɫ77777þ| Ʒþþþþþ˿| Ʒ99þþþþö | ɫۺϾþ| AVҰ¾þ| þˬһ| þþƷһպ| þþžȫ| ݺɫۺϾþ| 99ŷƷþþѿ| þþþ޾Ʒһ | һþöۺ| Ʒþþ99| þþƷAV| 91þþƷ91ɫҲ|