.net研究院之多线程技术6-异常处理-线程间通知-临时变量-线程安全&Lock

多线程的异常处理示例

线程异常后经常是需要通知别的线程,而不是等到WaitAll,问题就是要线程取消
工作中常规建议:多线程的委托里面不允许异常,包一层try-catch,然后记录下来异常信息,完成需要的操作

 

如果某一个线程异常了,需要通知或终止其他线程示例

//多线程并发任务,某个失败后,希望通知别的线程,都停下来,how?
//Thread.Abort--终止线程;向当前线程抛一个异常然后终结任务;线程属于OS资源,可能不会立即停下来
//Task不能外部终止任务,只能自己终止自己(上帝才能打败自己)

//cts有个bool属性IsCancellationRequested 初始化是false
//调用Cancel方法后变成true(不能再变回去),可以重复cancel
try
{
    CancellationTokenSource cts = new CancellationTokenSource();
    List<Task> taskList = new List<Task>();
    for (int i = 0; i < 50; i++)
    {
        string name = $"btnThreadCore_Click_{i}";
        taskList.Add(Task.Run(() =>
        {
            try
            {
                //判断cts.IsCancellationRequested,如果其他线程已经出现异常了,则终止线程内的任务
                if (!cts.IsCancellationRequested)
                    Console.WriteLine($"This is {name} 开始 ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");

                Thread.Sleep(new Random().Next(50, 100));

                if (name.Equals("btnThreadCore_Click_11"))
                {
                    throw new Exception("btnThreadCore_Click_11异常");
                }
                else if (name.Equals("btnThreadCore_Click_12"))
                {
                    throw new Exception("btnThreadCore_Click_12异常");
                }
                else if (name.Equals("btnThreadCore_Click_13"))
                {
                    cts.Cancel();
                }
                //可以在多个核心位置进行判断
                if (!cts.IsCancellationRequested)
                {
                    Console.WriteLine($"This is {name}成功结束 ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                }
                else
                {
                    Console.WriteLine($"This is {name}中途停止 ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
                    return;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                //捕获到其中一个线程异常,则调用cts.Cancel()
                cts.Cancel();
            }
        //也可以在Task.run的参数里传递cts.Token,当出现异常后即不再启动(创建)后续的线程
        }, cts.Token));
    }
    //1 准备cts  2 try-catch-cancel  3 Action要随时判断IsCancellationRequested
    //尽快停止,肯定有延迟,在判断环节才会结束

    Task.WaitAll(taskList.ToArray());
    //如果线程还没启动,能不能就别启动了?
    //1 启动线程传递Token  2 异常抓取  
    //在Cancel时还没有启动的任务,就不启动了;也是抛异常,cts.Token.ThrowIfCancellationRequested
}
//AggregateException是专门捕获线程异常的
catch (AggregateException aex)
{
    foreach (var exception in aex.InnerExceptions)
    {
        Console.WriteLine(exception.Message);
    }
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}

临时变量

#region 临时变量
{
    //for (int i = 0; i < 5; i++)
    //{
    //    Task.Run(() =>
    //    {
    //        最终i显示都是5
    //        Console.WriteLine($"This is btnThreadCore_Click_{i} ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
    //    });
    //}
    //处理方法
    //临时变量问题,线程是非阻塞的,延迟启动的;线程执行的时候,i已经是5了
    //k是闭包里面的变量,每次循环都有一个独立的k
    //5个k变量  1个i变量
    for (int i = 0; i < 5; i++)
    {
        int k = i;
        Task.Run(() =>
        {
            Console.WriteLine($"This is btnThreadCore_Click_{i}_{k} ThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
        });
    }
}
#endregion

 

Lock

Lock锁是排斥其他线程!!

推荐使用的lock锁变量

private static readonly object Form_Lock = new object();

线程安全:如果你的代码在进程中有多个线程同时运行这一段,如果每次运行的结果都跟单线程运行时的结果一致,那么就是线程安全的
线程安全问题一般都是有全局变量/共享变量/静态变量/硬盘文件/数据库的值,只要多线程都能访问和修改
发生是因为多个线程相同操作,出现了覆盖,怎么解决?
1 Lock解决多线程冲突
Lock是语法糖,Monitor.Enter,占据一个引用,别的线程就只能等着
推荐锁是private static readonly object,
A不能是Null,可以编译不能运行;
B 不推荐lock(this),外面如果也要用实例,就冲突了
C 不应该是string; string在内存分配上是重用的,会冲突
D Lock里面的代码不要太多,这里是单线程的
 

 

线程安全问题

1.使用官方的线程安全集合,在改集合内进行多线程操作

// 线程安全集合
System.Collections.Concurrent.ConcurrentQueue<int>

2.数据分拆,避免多线程操作同一个数据;又安全又高效,这才是最顶的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值