zoukankan      html  css  js  c++  java
  • C#中级-常用多线程操作(持续更新)

    一、前言

          多线程操作一直是编程的常用操作,掌握好基本的操作可以让程序运行的更加有效。本文不求大而全,只是将我自己工作中常常用到的多线程操作做个分类和总结。平时记性不好的时候还能看看。本文参考了多篇园子里的精彩博文,在文章最后会贴出具体来源,感谢他们的无私奉献。

    二、关于线程

    (1) 为何使用线程:

          可以使用线程将代码同其他代码隔离,提高应用程序的可靠性;

          可以使用线程来简化编码;

          可以使用线程来实现并发执行。

    (2) 进程、应用程序域以及线程的关系:

          进程(Process)是Windows系统中的一个基本概念,它包含着一个运行程序所需要的资源。进程之间是相对独立的,一个进程无法访问另一个进程的数据(除非利用分布式计算方式),一个进程运行的失败也不会影响其他进程的运行,Windows系统就是利用进程把工作划分为多个独立的区域的。进程可以理解为一个程序的基本边界。

          应用程序域(AppDomain)是一个程序运行的逻辑区域,它可以视为一个轻量级的进程,.NET的程序集正是在应用程序域中运行的,一个进程可以包含有多个应用程序域,一个应用程序域也可以包含多个程序集。在一个应用程序域中包含了一个或多个上下文context,使用上下文CLR就能够把某些特殊对象的状态放置在不同容器当中。

          线程(Thread)是进程中的基本执行单元,在进程入口执行的第一个线程被视为这个进程的主线程。

          关系图如下:

    三、Thread

          Thread可能是除了Task之外用的最多的多线程类。一般用法:

    // one thread
    Thread thread = new ThreadStart(functiion);
    thread.Start();
    
    // thread.join
    Thread ThreadA = new Thread(delegate()
    {
      //do something      
    });
      
    Thread ThreadB = new Thread(delegate()
    {       
      //do something;  
      
          ThreadA.Join();
      
      //do another thing      
    });
      
    //启动线程
    ThreadA.Start();
    ThreadB.Start();
    
    //一开始,两个线程相互交替运行,当线程B运行到线程A的join时,会先让线程A执行完,然后线程B再继续执行。你可以理解为超车,一开始两者互不相让,当join时,线程A超车了线程B

    四、ThreadPool

            由于线程的创建和销毁需要耗费一定的开销,过多的使用线程会造成内存资源的浪费,出于对性能的考虑,于是引入了线程池的概念。线程池维护一个请求队列,线程池的代码从队列提取任务,然后委派给线程池的一个线程执行,线程执行完不会被立即销毁,这样既可以在后台执行任务,又可以减少线程创建和销毁所带来的开销。

           如果一个线程的时间非常长,就没必要用线程池了(不是不能作长时间操作,而是不宜。),况且我们还不能控制线程池中线程的开始、挂起、和中止。

    ThreadPool.QueueUserWorkItem(function,parameter);

    五、Task

          Task是我用的最多的多线程方式,一般使用的方法如下:  

    // one task
    var task = new Task(() =>{
    // do something
    }); task.Start();
    // task one by one
    var task = new Task(() =>{
     // do something  
    });

    Task task2 = task.ContinueWith(()=>{
    // do something  
    });
    task.Start();

    //
    many tasks var tasks = new Task[PackCount]; //多线程任务 for (int index = 0; index < PackCount; index++) { int Threadindex = index; var task = new Task(() => { // do something } }); tasks[Threadindex] = task; task.Start(); } Task.WaitAll(tasks); //等待所有线程完成 //Task.WaitAny(tasks); //等待一个线程完成继续执行主程序

    //Task.Factory
    Task.Factory.StartNew(()=>{ // do something });

    六、Invoke、BeginInvoke、DynamicInvoke

          此处主要说明的是delegate下的各种Invoke

          Invoke (委托方法执行在调用处同一个线程中

    delegate void MyDelegate();
    
    MyDelegate del = new MyDelegate(Function);
    del .Invoke();     //使用到委托的invoke方法

          BeginInvoke(它从线程池中抓取一个空闲线程,来委托执行方法)

    A情况:使用IAsyncResult.IsCompleted判断子线程是否执行完毕

    delegate T MyDelegate();
    
    MyDelegate del = new MyDelegate(Function);
    
    IAsyncResult result = del.BeginInvoke(parameter,null,null);
    
    //if the branch thread is not completed
    while(!result.IsCompleted)  
    {
        // the main thread do another thing
    }
    
    T data = del.EndInvoke(result); 
    // var data is the result of Function with parameter

    B情况:使用IAsyncResult.AsyncWaitHandle.WaitOne(timeout)判断子线程是否执行完毕

    delegate T MyDelegate();
    
    MyDelegate del = new MyDelegate(Function);
    
    IAsyncResult result = del.BeginInvoke(parameter,null,null);
    
    //if the branch thread is not completed
    while(!result.AsyncWaitHandle.WaitOne(int timeout))  
    {
        // the main thread do another thing
    }
    
    T data = del.EndInvoke(result); 
    // var data is the result of Function with parameter

    C情况:使用WaitHandle.WaitAll(WaitHandle[],timeout)判断子线程是否执行完毕

    delegate T MyDelegate();
    
    MyDelegate del = new MyDelegate(Function);
    
    IAsyncResult result = del.BeginInvoke(parameter,null,null);
    
    WaitHandle[] waitHandleList = new WaitHandle[] { result.AsyncWaitHandle,........ };
    
    while (!WaitHandle.WaitAll(waitHandleList,int timeout))
    {
        // the main thread do another thing
    }
    
    T data = del.EndInvoke(result); 
    // var data is the result of Function with parameter

    D情况:使用轮询方式来检测异步方法的状态非常麻烦,而且效率不高,为此需要使用回调函数。主线程可以安心做自己的事,而异步线程完成操作后执行回调函数即可。回调函数依然是在异步线程上,而非主线程上。

    delegate T MyDelegate();
    
    MyDelegate del = new MyDelegate(Function);
    
    IAsyncResult result = del.BeginInvoke(parameter,new AsyncCallback(callbackFunction),object);
    
    ....MainThread do somethng...
    
    static void callbackFunction(IAsyncResult result)
    {
         AsyncResult  _result = (AsyncResult )result;
    
         MyDelegate del = (MyDelegate)_result.AsyncDelegate;
    
         T data = del.EndInvoke(_result);
    
         T1 objectReciever = (T1)result.AsyncResult; //object=result.AsyncResult
    }

            DynamicInvoke:

           与Delegate.Invoke类似,同步,且同线程,唯一不同的是,是采用后期绑定的方式来调用委托方法,所以时间代价较大。

    工作实例:在WPF中出现一种异常:“调用线程无法访问此对象,因为另一个线程拥有该对象。

    情况A:假设发生该异常的代码是在xaml.cs文件中,那么Dispatcher.Invoke已经够用了。

    情况B: 假设发生该异常的代码是在.cs文件中,那么在Stack Overflow上有一招:

     1 private void RaiseEventOnUIThread(Delegate theEvent, object[] args)
     2 {
     3       foreach (Delegate d in theEvent.GetInvocationList())
     4       {
     5             ISynchronizeInvoke syncer = d.Target as ISynchronizeInvoke;
     6             if (syncer == null)  //静态函数为null
    7 { 8 d.DynamicInvoke(args); 9 } 10 else 11 { 12 syncer.BeginInvoke(d, args); //在创建了此对象的线程上异步执行委托 13 } 14 } 15 }

        

    References:

    【1】http://blog.sina.com.cn/s/blog_5a6f39cf0100qtzf.html

    【2】http://www.cnblogs.com/slikyn/articles/1525940.html

    【3】http://kb.cnblogs.com/page/130487/#t3

    【4】http://blog.csdn.net/soft_123456/article/details/38819877

    【5】http://www.cnblogs.com/laoyur/archive/2011/04/14/2016025.html

    【6】http://blog.csdn.net/cselmu9/article/details/8274556

    【7】http://stackoverflow.com/questions/1698889/raise-events-in-net-on-the-main-ui-thread

  • 相关阅读:
    微支付开发(.net)
    微信公众平台开发(一) 配置接口
    [040] 微信公众帐号开发教程第16篇-应用实例之历史上的今天
    [039] 微信公众帐号开发教程第15篇-自定义菜单的view类型(访问网页)
    [038] 微信公众帐号开发教程第14篇-自定义菜单的创建及菜单事件响应
    [037] 微信公众帐号开发教程第13篇-图文消息全攻略
    【微网站开发】之微信内置浏览器API使用
    .Net(c#)汉字和Unicode编码互相转换
    jquery.uploadify上传文件配置详解(asp.net mvc)
    微信公众平台入门开发教程.Net(C#)框架
  • 原文地址:https://www.cnblogs.com/lovecsharp094/p/6104743.html
Copyright © 2011-2022 走看看