C#多线程之篇(上)
前言
抛开死锁不谈,只聊性能问题,尽管锁总能粗暴的满足同步需求,但一旦存在竞争关系,意味着一定会有线程被阻塞,竞争越激烈,被阻塞的线程越多,上下文切换次数越多,调度成本越大,显然在高并发的场景下会损害性能。在高并发高性能且要求线程安全的述求下,无锁构造(非阻塞构造)闪亮登场。
参考文档:
C# - 理论与实践中的 C# 内存模型,第 2 部分 | Microsoft Docs
volatile 关键字 (C# 参考)
一、非阻塞同步
重排序与缓存
我们观察下面这个例子:
public class Foo
{
private int _answer;
private bool _complete;
void A() //A 1
{
_answer = 10;
_complete = true;
}
void B() //B 2
{
if (_complete) Console.WriteLine(_answer);
}
}
如果方法A
和B
在不同的线程上并发运行,B
可能会打印 “ 0 “ 吗?答案是会的,原因如下:
- 编译器、CLR 或 CPU 可能会对代码/指令进行重排序(reorder)以提高效率。
- 编译器、CLR 或 CPU 可能会进行缓存优化,导致其它线程不能马上看到变量的新值。
请务必重视它们,它们将是幽灵般的存在
int x = , y = , a = , b = ;
var task1 = Task.Run(() => // A 1
{
a = 1; // 1
x = b; // 2
});
var task2 = Task.Run(() => // B 2
{
b = 2; // 3
y = a; // 4
});
Task.WaitAll(task1, task2);
Console.WriteLine("x:" + x + " y:" + y);
直觉和经验告诉我们,程序至顶向下执行:代码1一定发生在代码2之前,代码3一定发生在代码4之前,然鹅
在一个独立的线程中,每一个语句的执行顺序是可以被保证的,但在不使用lock,waithandle这样的显式同步操作时,我们就没法保证事件在不同的线程中看到的执行顺序是一致的了。尽管线程A中一定需要观察到a=1执行成功之后才会去执行x=b,但它没法确保自己观察得到线程B中对b的写入,所以A还可能会打印出y的一个旧版的值。这就叫指令重排序。
x:0 y:1 #1-2-3-4
x:2 y:0 #3-4-1-2
x:2 y:1 #1-3-2-4
可实际运行时还是有些让我们惊讶的情况:
x:0 y:0 #??
这就是缓存问题,如果两个线程在不同的CPU上执行,每一个核心有自己的缓存,这样一个线程的写入对于其它线程,在主存同步之前就是不可见的了。
C#编译器和CLR运行时会非常小心的保证上述优化不会破坏普通的单线程代码,和正确使用锁的多线程代码。但有时,你仍然需要通过显示的创建内存屏障(memory barrier,也称作内存栅栏 (memory fence))来对抗这些优化,限制指令重排序和读写缓存产生的影响。
内存屏障
参考博客小林野夫
处理器支持哪种内存重排序(LoadLoad重排序、LoadStore重排序、StoreStore重排序、StoreLoad重排序),就会提供相对应能够禁止重排序的指令,而这些指令就被称之为内存屏障(LoadLoad屏障、LoadStore屏障、StoreStore屏障、StoreLoad屏障)
屏障名称 | 示例 | 具体作用 |
---|---|---|
StoreLoad | Store1;Store2;Store3;StoreLoad;Load1;Load2;Load3 | 禁止StoreLoad重排序,确保屏障之前任何一个写(如Store2)的结果都会在屏障后任意一个读操作(如Load1)加载之前被写入 |
StoreStore | Store1;Store2;Store3;StoreStore;Store4;Store5;Store6 | 禁止StoreStore重排序,确保屏障之前任何一个写(如Store1)的结果都会在屏障后任意一个写操作(如Store4)之前被写入 |
LoadLoad | Load1;Load2;Load3;LoadLoad;Load4;Load5;Load6 | 禁止LoadLoad重排序,确保屏障之前任何一个读(如Load1)的数据都会在屏障后任意一个读操作(如Load4)之前被加载 |
LoadStore | Load1;Load2;Load3;LoadStore;Store1;Store2;Store3 | 禁止LoadStore重排序,确保屏障之前任何一个读(如Load1)的数据都会在屏障后任意一个写操作(如Store1)的结果被写入高速缓存(或主内存)前被加载 |
相关文章