C#多线程学习笔记二

线程可见

AllocateDataSlot、SetData、 GetData

variable var => thread t1,t2
(1) t1,t2 共享var => public 有“锁”的问题
(2) t1,t2 各自有一个var => internal 没有锁争用的问题

var slot = Thread.AllocateDataSlot("username");
//主线程上设置槽位,也就是说hello word只能被主线程读取,其他线程无法读取
Thread.SetData(slot, "hello word!!");
new Thread(() => 
{
    
    
Thread.SetData(slot, "hello!!");
var obj = Thread.GetData(slot); 
Console.WriteLine("子线程:{0}",obj); 
}).Start();
var obj2 = Thread.GetData(slot);
Console.WriteLine("主线程:{0}",obj2);
Console.ReadKey();

输出结果:属于情况(2)
在这里插入图片描述

性能提升版:ThreadStatic

[ThreadStatic]
static string username = "??!!";
static void Main(string[] args)
{
    
    
username = "hello word!!";
new Thread(() =>
{
    
    
username = "hello!!";
Console.WriteLine("子线程:{0}", username);
}).Start();
    Console.WriteLine("主线程:{0}", username);
    Console.ReadKey();
}

运行结果:属于情况(2)
在这里插入图片描述

ThreadLocal:也叫做线程可见性

ThreadLocal<string> local = new ThreadLocal<string>();
local.Value = "hello word!!";
new Thread(() =>
{
    
    
local.Value = "hello!!";
Console.WriteLine("子线程:{0}", local.Value);
}).Start();
Console.WriteLine("主线程:{0}", local.Value);
Console.ReadKey();

运行结果:属于情况(2)
在这里插入图片描述

总结

这些数据都是存放在线程环境快中,是线程的空间开销。

内存栏栅

release和debug的性能差异

实际项目中,发布版本都是release版本,而不是debug版本,因为release中做了一些代码和缓存的优化,比如将一些数据从memory中读取到CPU高速缓存中。这一操作可能会带来一些bug。

下面这段代码在release环境下出现主线程不能执行结束的问题。

var isStop = false;
Thread t = new Thread(() =>
{
    
    
    var isSuccess = false;
    while (!isStop)
    {
    
    
        isSuccess = !isSuccess;
    }
});
t.Start();
Thread.Sleep(1000);
isStop = true;
t.Join();
Console.WriteLine("主线程执行结束");
Console.ReadKey();

从代码中可以发现两个线程在共用一个isStop变量,而线程t会将该变量加载到CPU Cache中,当主线程对isStop进行修改后,线程t感知不到。
两个解决方法:
1. 不要让多个线程去操作一个共享变量,否则容易出现问题。
2. 如果一定要这么做,则需要不进行缓存,每次都从memory中读取数据。

MemoryBarrier和VolatileRead

在此方法之前的内存写入都要及时从CPU Cache中更新到memory,在此方法之后的内存读取都要从memory中读取而不是CPU Cache。
MemoryBarrier:

var isStop = false;
Thread t = new Thread(() =>
{
    
    
    var isSuccess = false;
    while (!isStop)
    {
    
    
       Thread.MemoryBarrier();
       isSuccess = !isSuccess;
    }
});
t.Start();
Thread.Sleep(1000);
isStop = true;
t.Join();
Console.WriteLine("主线程执行结束");
Console.ReadKey();

VolatileRead:

var isStop = 0;
Thread t = new Thread(() =>
{
    
    
   var isSuccess = false;
   while (isStop != 1)
   {
    
       
      Thread.VolatileRead(ref isStop);
      isSuccess = !isSuccess;
   }
});
t.Start();
Thread.Sleep(1000);
isStop = 1;
t.Join();
Console.WriteLine("主线程执行结束");
Console.ReadKey();

猜你喜欢

转载自blog.csdn.net/Z960515/article/details/113434841