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");

               }。

  • 相关阅读:
    在eclipse外边打开浏览器
    双开Eclipse
    6.5版本的CentOSLinux
    Intel x86_64 Architecture Background 3
    Java 大数、高精度模板
    Intel x86_64 Architecture Background 2
    Intel x86_64 Architecture Background 1
    Codeforces 999D Equalize the Remainders (set使用)
    Codeforces 996E Leaving the Bar (随机化)
    欧拉函数(小于或等于n的数中与n互质的数的数目)&& 欧拉函数线性筛法
  • 原文地址:https://www.cnblogs.com/yaopengfei/p/7071515.html
Copyright © 2011-2022 走看看