zoukankan      html  css  js  c++  java
  • .Net进阶系列(15)-异步多线程(线程的特殊处理和深究委托赋值)(被替换)

    1. 线程的异常处理

     我们经常会遇到一个场景,开启了多个线程,其中一个线程报错,导致整个程序崩溃。这并不是我们想要的,我需要的结果是,其中一个线程报错,默默的记录下,其它线程正常进行,保证程序整体可以走下来。

      解决方案:给函数体加try-catch,只让报错线程异常,其它线程可以正常进行。

     1         private void button7_Click(object sender, EventArgs e)
     2         {
     3             Stopwatch watch = new Stopwatch();
     4             watch.Start();
     5             Console.WriteLine("----------------- 八.线程的特殊处理  --------------------------");
     6             Console.WriteLine("----------------- button7_Click 开始 主线程id为:{0}  --------------------------", Thread.CurrentThread.ManagedThreadId);
     7             try
     8             {
     9 
    10                 TaskFactory taskFactory = new TaskFactory();
    11                 List<Task> taskList = new List<Task>();
    12 
    13                 #region 01-异常处理
    14                 {
    15                     for (int i = 0; i < 5; i++)
    16                     {
    17                         string name = string.Format("button_Click{0}", i);
    18                         Action<object> act = t =>
    19                         {
    20                             try
    21                             {
    22                                 //模拟报错
    23                                 if (t.ToString().Equals("button_Click2"))
    24                                 {
    25                                     throw new Exception(string.Format("{0} 执行失败", t));
    26                                 }
    27                                 Console.WriteLine("{0} 执行成功", t);
    28                             }
    29                             catch (Exception ex)
    30                             {
    31                                 Console.WriteLine(ex.Message);
    32                             }
    33                         };
    34                         Task task = taskFactory.StartNew(act, name);
    35                         taskList.Add(task);
    36                     }
    37                     //线程等待
    38                     Task.WaitAll(taskList.ToArray());
    39                 }
    40                 #endregion
    41 
    44             }
    45             catch (AggregateException aes)
    46             {
    47                 foreach (var item in aes.InnerExceptions)
    48                 {
    49                     Console.WriteLine(item.Message);
    50                 }
    51             }
    52             catch (Exception ex)
    53             {
    54                 Console.WriteLine(ex.Message);
    55             }
    56 
    57             watch.Stop();
    58             Console.WriteLine("----------------- button7_Click 结束 主线程id为:{0}  总耗时:{1}--------------------------", Thread.CurrentThread.ManagedThreadId, watch.ElapsedMilliseconds);
    59 
    60         }

    运行结果:

    2.  线程的取消

          线程不能主动取消,只能通过信号量的形式进行检查,接到取消指令后,后续的线程都将取消。

     1  {
     2                     //Task不能主动取消,只能通过信号量检查的方式
     3                     CancellationTokenSource cts = new CancellationTokenSource();
     4                     for (int i = 0; i < 10; i++)
     5                     {
     6                         string name = string.Format("button_Click{0}", i);
     7                         Action<object> act = t =>
     8                         {
     9                             try
    10                             {
    11                                 Thread.Sleep(2000);
    12                                 //模拟报错
    13                                 if (t.ToString().Equals("button_Click2"))
    14                                 {
    15                                     throw new Exception(string.Format("{0} 执行失败", t));
    16                                 }
    17                                 if (cts.IsCancellationRequested)
    18                                 {
    19                                     Console.WriteLine("{0} 放弃执行", t);
    20                                 }
    21                                 else
    22                                 {
    23                                     Console.WriteLine("{0} 执行成功", t);
    24                                 }
    25                             }
    26                             catch (Exception ex)
    27                             {
    28                                 cts.Cancel();    //凡是在 button_Click2 的执行线程后执行的,均被放弃了执行
    29                                 Console.WriteLine(ex.Message);
    30                             }
    31                         };
    32                         Task task = taskFactory.StartNew(act, name, cts.Token);
    33                         taskList.Add(task);
    34                     }
    35                     //线程等待
    36                     Task.WaitAll(taskList.ToArray());
    37                 }

    运行结果:

     

    3.  多线程临时变量

     1  {
     2                     for (int i = 0; i < 5; i++)
     3                     {
     4                         int k = i;
     5                         Action act = () =>
     6                         {
     7                             Console.WriteLine(k);   //0,1,2,3,4  不一定按照顺序
     8                             Console.WriteLine(i);   //全为5
     9                         };
    10                         act.BeginInvoke(null, null);
    11                     }
    12 }

    4. 线程安全

     当多个线程同时操控一个全局变量时,需要加锁,来保证线程安全。其中锁变量为 私有的静态object变量。eg: private static object btnThreadCore_Click_Lock = new object();

     1                 {
     2                     for (int i = 0; i < 10000; i++)
     3                     {
     4                         Task task = taskFactory.StartNew(() =>
     5                         {
     6                             //只有方法外的变量需要加锁
     7                             int k = 2;
     8                             lock (btnThreadCore_Click_Lock)
     9                             {
    10                                 this.TotalCount += 1;
    11                             }
    12                         });
    13                         taskList.Add(task);
    14                     }
    15                     //线程等待
    16                     Task.WaitAll(taskList.ToArray());
    17                     //测试输出结果
    18                     Console.WriteLine(this.TotalCount);   //当不加线程锁的时候,结果不一定是10000,加锁后,一定为10000
    19                 }

    5. 委托的几种赋值形式

          三个方法:TestThread()、TestThread2(string name)、TestThread(string name,string pwd)。

          形式一:声明的委托参数和要赋值的函数参数意义对应

          eg:    Action act1=TestThread ;

                      Action<string> act2=TestThread2;

                      Action<string,string> act3=TestThread3;

    注意:这种形式,需要在委托被调用的时候将函数所需的参数值传递进去。

          形式二: 声明无参数委托,但利用()=>进行将有参数的函数转换,可以直接将参数所需的值传递进去,委托调用的时候,将不需要再传递了。

          eg:    Action act1=TestThread ;

                      Action act2=()=>TestThread2("测试参数1");

                      Action act3=()=>TestThread3("测试参数1","测试参数2");

     注意:这种形式,实际上就是直接将函数体赋值给委托,但又把一个函数当做内容传递到了这个函数体内,实际上

                Action act2=()=>TestThread2("测试参数1");   等价于

                Action act2=()=>{

                TestThread2("测试参数1");

               }。

           形式三: 直接将函数体赋值给委托,然后函数体中的内容为一个新的函数,这种形式,需要在委托被调用的时候将函数所需的参数值传递进去。

    eg:           Action act1=TestThread ;

                      Action act2=t=>TestThread2(t);

                      Action act3=(m,n)=>TestThread3(m,n);

     注意:这种形式,实际上就是直接将函数体赋值给委托,但又把一个函数当做内容传递到了这个函数体内,实际上

                Action act2=t=>TestThread2(t);   等价于

                Action act2=(t)=>{

                TestThread2("测试参数1");

               }。

  • 相关阅读:
    Building a flexiable renderer
    Indirect Illumination in mental ray
    我的心情
    Cellular Automata
    Subsurface Scattering in mental ray
    Shader Types in mental ray
    BSP Traversal
    我的渲染器终于达到了MR的速度
    How to handle displacement and motion blur
    说明
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/7071515.html
Copyright © 2011-2022 走看看