使用Thread的一些注意事项
线程可见
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();