• 如何保证对象在线程内唯一


    背景:为了解决多线程竞用共享资源的问题,引入数据槽的概念,即将数据存放到线程的环境块中,使该数据只能单一线程访问.(属于线程空间上的开销)

      下面的三种方式是解决多线程竞用共享资源的通用方式:

      ①:AllocateNamedDataSlot命名槽位和AllocateDataSlot未命名槽位 解决线程竞用资源共享问题。

      (PS:在主线程上设置槽位,使该数据只能被主线程读取,其它线程无法访问)

    复制代码
       private void button10_Click(object sender, EventArgs e)
            {
                #region 01-AllocateNamedDataSlot命名槽位
                {
                    var d = Thread.AllocateNamedDataSlot("userName");
                    //在主线程上设置槽位,使该数据只能被主线程读取,其它线程无法访问
                    Thread.SetData(d, "ypf");
                    //声明一个子线程
                    var t1 = new Thread(() =>
                    {
                        Console.WriteLine("子线程中读取数据:{0}", Thread.GetData(d));
                    });
                    t1.Start();
    
                    //主线程中读取数据
                    Console.WriteLine("主线程中读取数据:{0}", Thread.GetData(d));
                }
    
                #endregion
    
                #region 02-AllocateDataSlot未命名槽位
                {
                    var d = Thread.AllocateDataSlot();
                    //在主线程上设置槽位,使该数据只能被主线程读取,其它线程无法访问
                    Thread.SetData(d, "ypf");
                    //声明一个子线程
                    var t1 = new Thread(() =>
                    {
                        Console.WriteLine("子线程中读取数据:{0}", Thread.GetData(d));
                    });
                    t1.Start();
    
                    //主线程中读取数据
                    Console.WriteLine("主线程中读取数据:{0}", Thread.GetData(d));
    
                }
                #endregion
    
            }
    复制代码

      ②:利用特性[ThreadStatic] 解决线程竞用资源共享问题

       (PS:在主线程中给ThreadStatic特性标注的变量赋值,则只有主线程能访问该变量,比数据槽性能好,使用方便)

      ③:利用ThreadLocal线程的本地存储, 解决线程竞用资源共享问题(线程可见性)

      (PS: 在主线程中声明ThreadLocal变量,并对其赋值,则只有主线程能访问该变量)

     

    ④ CallContext 线程内可见。当 CallContext 沿执行代码路径往返传播并且由该路径中的各个对象检查时,可将对象添加到其中。
    使用场景:当对象需要线程内全局使用。Core不支持

    CallContext.SetData(key, temp);
    DbContext temp = CallContext.GetData(key) as DbContext;

    四. 内存栅栏-线程共享资源

    背景:当多个线程共享一个变量的时候,在Release模式的优化下,子线程会将共享变量加载的cup Cache中,导致主线程不能使用该变量而无法运行。

    内存栅栏:变量在进入内存栅栏并读取时,变量的值已经写入完毕,离开栅栏时,变量的值被读取时也已经写入完毕

    解决方案:

      ①:不要让多线程去操作同一个共享变量,从根本上解决这个问题。

      ②:利用MemoryBarrier方法进行处理,在此方法之前的内存写入都要及时从cpu cache中更新到 memory;在此方法之后的内存读取都要从memory中读取,而不是cpu cache。

      ③:利用VolatileRead/Write方法进行处理。

    a = 0 , b = 0;
    void fun1() {   
      a = 1;   
      b = 1;
    }
    
    void fun2() {  
      while (b == 0) continue;  
      assert(a == 1);
    }

     如果 一个线程执行 fun1(),另一个线程执行 fun2时,当b=1,a一定等于 1吗,答案是 不一定,a还有可能是0  具体请看 https://zhuanlan.zhihu.com/p/125737864

    复制代码
     1  private void button11_Click(object sender, EventArgs e)
     2         {
     3             #region 01-默认情况(Release模式主线程不能正常运行)
     4             //{
     5             //    var isStop = false;
     6             //    var t = new Thread(() =>
     7             //    {
     8             //        var isSuccess = false;
     9             //        while (!isStop)
    10             //        {
    11             //            isSuccess = !isSuccess;
    12             //        }
    13             //        Console.WriteLine("子线程执行成功");
    14             //    });
    15             //    t.Start();
    16 
    17             //    Thread.Sleep(1000);
    18             //    isStop = true;
    19 
    20             //    t.Join();
    21             //    Console.WriteLine("主线程执行结束");
    22             //}
    23             #endregion
    24 
    25             #region 02-MemoryBarrier解决共享变量(Release模式下可以正常运行)
    26             //{
    27             //    var isStop = false;
    28             //    var t = new Thread(() =>
    29             //    {
    30             //        var isSuccess = false;
    31             //        while (!isStop)
    32             //        {
    33             //            Thread.MemoryBarrier();
    34 
    35             //            isSuccess = !isSuccess;
    36             //        }
    37             //        Console.WriteLine("子线程执行成功");
    38             //    });
    39             //    t.Start();
    40 
    41             //    Thread.Sleep(1000);
    42             //    isStop = true;
    43 
    44             //    t.Join();
    45             //    Console.WriteLine("主线程执行结束");
    46             //}
    47             #endregion
    48 
    49             #region 03-VolatileRead解决共享变量(Release模式下可以正常运行)
    50             {
    51                 var isStop = 0;
    52                 var t = new Thread(() =>
    53                 {
    54                     var isSuccess = false;
    55                     while (isStop == 0)
    56                     {
    57                         Thread.VolatileRead(ref isStop);
    58 
    59                         isSuccess = !isSuccess;
    60                     }
    61                     Console.WriteLine("子线程执行成功");
    62                 });
    63                 t.Start();
    64 
    65                 Thread.Sleep(1000);
    66                 isStop = 1;
    67 
    68                 t.Join();
    69                 Console.WriteLine("主线程执行结束");
    70             }
    71             #endregion
    72 
    73 
    74         }
    复制代码
  • 相关阅读:
    Linux命令应用大词典-第11章 Shell编程
    Kubernetes 学习12 kubernetes 存储卷
    linux dd命令
    Kubernetes 学习11 kubernetes ingress及ingress controller
    Kubernetes 学习10 Service资源
    Kubernetes 学习9 Pod控制器
    Kubernetes 学习8 Pod控制器
    Kubernetes 学习7 Pod控制器应用进阶2
    Kubernetes 学习6 Pod控制器应用进阶
    Kubernetes 学习5 kubernetes资源清单定义入门
  • 原文地址:https://www.cnblogs.com/wwkk/p/13290309.html
Copyright © 2020-2023  润新知