欢迎来到淘文阁 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
淘文阁 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    VC#中的多线程编程.doc

    • 资源ID:33471635       资源大小:56.50KB        全文页数:8页
    • 资源格式: DOC        下载积分:15金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要15金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    VC#中的多线程编程.doc

    如有侵权,请联系网站删除,仅供学习与交流VC#中的多线程编程【精品文档】第 8 页Visual C#中的多线程编程C#是.Net平台的通用开发工具,它能够建造所有的.Net应用。在.Net中所有线程都运行在应用程序域(AppDomain)中,这也许让你想到Win32进程,实际上它们还是有很大的不同。应用程序域提供了一种安全而通用的处理单元,公共语言运行库可使用它来隔离应用程序。注意在.Net中应用程序的隔离是应用程序域而不是进程,在单个进程中可以存在几个应用程序域,而且线程可以跨越应用程序域的范围,某个线程中的方法可以调用另一个线程的方法,这样的话就不会造成进程间调用或进程间切换等方面的额外开销。可以说应用程序域是物理进程(也即win32中的Process)内的逻辑进程。在Visul C#中System.Threading 命名空间提供一些使得可以进行多线程编程的类和接口,其中线程的创建有以下三种方法:Thread、ThreadPool、Timer。下面我就它们的使用方法逐个作一简单介绍。1 Thread这也许是最复杂的方法,但它提供了对线程的各种灵活控制。首先你必须使用它的构造函数创建一个线程实例,它的参数比较简单,只有一个ThreadStart 委托:C#public Thread(ThreadStart start);然后调用Start()启动它,当然你可以利用它的Priority属性来设置或获得它的运行优先级(enum ThreadPriority:  Normal、 Lowest、 Highest、 BelowNormal、 AboveNormal)。见下例:它首先生成了两个线程实例t1和t2,然后分别设置它们的优先级,接着启动两线程(两线程基本一样,只不过它们输出不一样,t1为“1”,t2为“2”,根据它们各自输出字符个数比可大致看出它们占用CPU时间之比,这也反映出了它们各自的优先级)。 static void Main(string args)     Thread t1 = new Thread(new ThreadStart(Thread1);   Thread t2 = new Thread(new ThreadStart(Thread2);   t1.Priority = ThreadPriority.BelowNormal  ;   t2.Priority = ThreadPriority.Lowest ;    t1.Start(); t2.Start();     public static void Thread1()      for (int i = 1; i < 1000; i+)    /每运行一个循环就写一个“1”dosth();    Console.Write("1");        public static void Thread2()      for (int i = 0; i < 1000; i+)    /每运行一个循环就写一个“2”    dosth();    Console.Write("2");       public static void dosth()  /用来模拟复杂运算   for (int j = 0; j < 10000000; j+)            int a=15;    a = a*a*a*a;     以上程序运行结果为:111111111111111111111111111111111111111111211111111111111111111111111111111111111111121111111111111111111111111111111111111111112111111111111111111111111111111111111111111211111111111111111111111111111111111111111121111111111111111111111111111111111111111112  从以上结果我们可以看出,t1线程所占用CPU的时间远比t2的多,这是因为t1的优先级比t2的高,若我们把t1和t2的优先级都设为Normal,那结果是如何?它们所占用的CPU时间会一样吗?是的,正如你所料,见下图: 121211221212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212121212   从上例我们可看出,它的构造类似于win32的工作线程,但更加简单,只需把线程要调用的函数作为委托,然后把委托作为参数构造线程实例即可。当调用Start()启动后,便会调用相应的函数,从那函数第一行开始执行。 接下来我们结合线程的ThreadState属性来了解线程的控制。ThreadState是一个枚举类型,它反映的是线程所处的状态。当一个Thread实例刚创建时,它的ThreadState是Unstarted;当此线程被调用Start()启动之后,它的ThreadState是 Running; 在此线程启动之后,如果想让它暂停(阻塞),可以调用Thread.Sleep() 方法,它有两个重载方法(Sleep(int )、Sleep(Timespan )),只不过是表示时间量的格式不同而已,当在某线程内调用此函数时,它表示此线程将阻塞一段时间(时间是由传递给 Sleep 的毫秒数或Timespan决定的,但若参数为0则表示挂起此线程以使其它线程能够执行,指定 Infinite 以无限期阻塞线程),此时它的ThreadState将变为WaitSleepJoin,另外值得注意一点的是Sleep()函数被定义为了static?! 这也意味着它不能和某个线程实例结合起来用,也即不存在类似于t1.Sleep(10)的调用!正是如此,Sleep()函数只能由需“Sleep”的线程自己调用,不允许其它线程调用,正如when to Sleep是个人私事不能由它人决定。但是当某线程处于WaitSleepJoin状态而又不得不唤醒它时,可使用Thread.Interrupt 方法 ,它将在线程上引发ThreadInterruptedException,下面我们先看一个例子(注意Sleep的调用方法):static void Main(string args)      Thread t1 = new Thread(new ThreadStart(Thread1);    t1.Start(); t1.Interrupt ();E.WaitOne ();t1.Interrupt ();   t1.Join();   Console.WriteLine(“t1 is end”);    static AutoResetEvent E = new AutoResetEvent(false);  public static void Thread1()        try   /从参数可看出将导致休眠    Thread.Sleep(Timeout.Infinite);       catch(System.Threading.ThreadInterruptedException e)   /中断处理程序    Console.WriteLine (" 1st interrupt");   E.Set ();   try   / 休眠    Thread.Sleep(Timeout.Infinite );       catch(System.Threading.ThreadInterruptedException e)   Console.WriteLine (" 2nd interrupt");   /暂停10秒    Thread.Sleep (10000);  运行结果为: 1st interrupt  2nd interrupt  (10s后)t1 is end 从上例我们可以看出Thread.Interrupt方法可以把程序从某个阻塞(WaitSleepJoin)状态唤醒进入对应的中断处理程序,然后继续往下执行(它的ThreadState也变为Running),此函数的使用必须注意以下几点:1 .此方法不仅可唤醒由Sleep导致的阻塞,而且对一切可导致线程进入WaitSleepJoin状态的方法(如Wait和Join)都有效。如上例所示, 使用时要把导致线程阻塞的方法放入try块内, 并把相应的中断处理程序放入catch块内。2 .对某一线程调用Interrupt, 如它正处于WaitSleepJoin状态, 则进入相应的中断处理程序执行, 若此时它不处于WaitSleepJoin状态, 则它后来进入此状态时, 将被立即中断。若在中断前调用几次Interrupt, 只有第一次调用有效, 这正是上例我用同步的原因, 这样才能确保第二次调用Interrupt在第一个中断后调用,否则的话可能导致第二次调用无效(若它在第一个中断前调用)。你可以把同步去掉试试,其结果很可能是:   1st interrupt上例还用了另外两个使线程进入WaitSleepJoin状态的方法:利用同步对象和Thread.Join方法。Join方法的使用比较简单,它表示在调用此方法的当前线程阻塞直至另一线程(此例中是t1)终止或者经过了指定的时间为止(若它还带了时间量参数),当两个条件(若有)任一出现,它立即结束WaitSleepJoin状态进入Running状态(可根据.Join方法的返回值判断为何种条件,为true,则是线程终止;false则是时间到)。线程的暂停还可用Thread.Suspend方法,当某线程处于Running状态时对它调用Suspend方法,它将进入SuspendRequested状态,但它并不会被立即挂起,直到线程到达安全点之后它才可以将该线程挂起,此时它将进入Suspended状态。如对一个已处于Suspended的线程调用则无效,要恢复运行只需调用Thread.Resume即可。  最后我们谈的是线程的销毁,我们可以对需销毁的线程调用Abort方法,它会在此线程上引发ThreadAbortException。我们可把线程内的一些代码放入try块内,并把相应处理代码放入相应的catch块内,当线程正执行try块内代码时如被调用Abort,它便会跳入相应的catch块内执行,执行完catch快内的代码后它将终止(若catch块内执行了ResetAbort则不同了:它将取消当前Abort请求,继续向下执行。所以如要确保某线程终止的最好用Join,如上例)。2 ThreadPool线程池(ThreadPool)是一种相对较简单的方法,它适应于一些需要多个线程而又较短任务(如一些常处于阻塞状态的线程) ,它的缺点是对创建的线程不能加以控制,也不能设置其优先级。由于每个进程只有一个线程池,当然每个应用程序域也只有一个线程池(对线),所以你将发现ThreadPool类的成员函数都为static! 当你首次调用ThreadPool.QueueUserWorkItem、ThreadPool.RegisterWaitForSingleObject等,便会创建线程池实例。下面我就线程池当中的两函数作一介绍:C#public static bool QueueUserWorkItem( 用成功则返回trueWaitCallback callBack,/要创建的线程调用的委托 object state  递给委托的参数)/它的另一个重载函数类似,只是委托不带参数而已 此函数的作用是把要创建的线程排队到线程池,当线程池的可用线程数不为零时(线程池有创建线程数的限制,缺身值为25),便创建此线程,否则就排队到线程池等到它有可用的线程时才创建。C#public static RegisteredWaitHandle RegisterWaitForSingleObject(   WaitHandle waitObject,/ 要注册的 WaitHandle   WaitOrTimerCallback callBack,/ 线程调用的委托   object state,/传递给委托的参数   int TimeOut,/超时,单位为毫秒,   bool executeOnlyOnce 否只执行一次); public delegate void WaitOrTimerCallback(   object state,/也即传递给委托的参数   bool timedOut/true表示由于超时调用,反之则因为waitObject); 此函数的作用是创建一个等待线程,一旦调用此函数便创建此线程,在参数waitObject变为终止状态或所设定的时间TimeOut到了之前,它都处于“阻塞”状态,值得注意的一点是此“阻塞”与Thread的WaitSleepJoin状态有很大的不同:当某Thread处于WaitSleepJoin状态时CPU会定期的唤醒它以轮询更新状态信息,然后再次进入WaitSleepJoin状态,线程的切换可是很费资源的;而用此函数创建的线程则不同,在触发它运行之前,CPU不会切换到此线程,它既不占用CPU的时间又不浪费线程切换时间,但CPU又如何知道何时运行它?实际上线程池会生成一些辅助线程用来监视这些触发条件,一旦达到条件便启动相应的线程,当然这些辅助线程本身也占用时间,但是如果你需创建较多的等待线程时,使用线程池的优势就越加明显。见下例:static AutoResetEvent ev=new AutoResetEvent(false); public static int Main(string args)   ThreadPool.RegisterWaitForSingleObject( ev, new WaitOrTimerCallback(WaitThreadFunc), 4, 2000, false/表示每次完成等待操作后都重置计时器,直到注销等待 );  ThreadPool.QueueUserWorkItem (new WaitCallback (ThreadFunc),8);  Thread.Sleep (10000);   return 0;     public static void ThreadFunc(object b)  Console.WriteLine ("the object is 0",b);  for(int i=0;i<2;i+)   Thread.Sleep (1000);   ev.Set();    public static void WaitThreadFunc(object b,bool t)  Console.WriteLine ("the object is 0,t is 1",b,t);    其运行结果为: the object is 8the object is 4,t is Falsethe object is 4,t is Falsethe object is 4,t is Truethe object is 4,t is Truethe object is 4,t is True从以上结果我们可以看出线程ThreadFunc运行了1次,而WaitThreadFunc运行了5次。我们可以从WaitOrTimerCallback中的bool t参数判断启动此线程的原因:t为false,则表示由于waitObject,否则则是由于超时。另外我们也可以通过object b向线程传递一些参数。3 Timer    它适用于需周期性调用的方法,它不在创建计时器的线程中运行,它在由系统自动分配的单独线程中运行。这和Win32中的SetTimer方法类似。它的构造为:C#public Timer(   TimerCallback callback,/所需调用的方法   object state,/传递给callback的参数   int dueTime,/多久后开始调用callback   int period/调用此方法的时间间隔);/ 如果 dueTime 为0,则 callback 立即执行它的首次调用。如果 dueTime 为 Infinite,则 callback 不调用它的方法。计时器被禁用,但使用 Change 方法可以重新启用它。如果 period 为0或 Infinite,并且 dueTime 不为 Infinite,则 callback 调用它的方法一次。计时器的定期行为被禁用,但使用 Change 方法可以重新启用它。如果 period 为零 (0) 或 Infinite,并且 dueTime 不为 Infinite,则 callback 调用它的方法一次。计时器的定期行为被禁用,但使用 Change 方法可以重新启用它。在创建计时器之后若想改变它的period和dueTime,我们可以通过调用Timer的Change方法来改变:C#public bool Change(   int dueTime,   int period);/显然所改变的两个参数对应于Timer中的两参数见下例:public static int   Main(string args)   Console.WriteLine ("period is 1000");  Timer tm=new Timer (new TimerCallback (TimerCall),3,1000,1000);  Thread.Sleep (2000);  Console.WriteLine ("period is 500");  tm.Change (0,800);  Thread.Sleep (3000);  return 0;       public static void TimerCall(object b)    Console.WriteLine ("timercallback; b is 0",b); 其运行结果为:period is 1000timercallback;b is 3 timercallback;b is 3 period is 500timercallback;b is 3 timercallback;b is 3 timercallback;b is 3 timercallback;b is 3    总结    从以上的简单介绍,我们可以看出它们各自使用的场合:Thread适用于那些需对线程进行复杂控制的场合;ThreadPool适应于一些需要多个线程而又较短任务(如一些常处于阻塞状态的线程);Timer则适用于那些需周期性调用的方法。只要我们了解了它们的使用特点,我们就可以很好的选择合适的方法。

    注意事项

    本文(VC#中的多线程编程.doc)为本站会员(豆****)主动上传,淘文阁 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知淘文阁 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

    收起
    展开