对linux内核中出现的种种同步和屏障,想做一点总结。

缓存一致性

之前一直认为linux中很多东西是用来保证缓存一致性的,其实不是。缓存一致性绝大部分是靠硬件机制实现的,只有在带lock前缀的指令执行时才与cache有一点关系。(这话说得绝对,但我目前看来就是这样)我们更多的时候是为了保证顺序一致性。

-

所谓缓存一致性,(大富网站源码架设修复Q_917_899_899 测试bbs.yasewl.com)就是在多处理器系统中,每个cpu都有自己的L1 cache。很可能两个不同cpu的L1 cache中缓存的是同一片内存的内容,如果一个cpu更改了自己被缓存的内容,它要保证另一个cpu读这块数据时也要读到这个最新的。不过你不要担心,这个复杂的工作完全是由硬件来完成的,通过实现一种MESI协议,硬件可以轻松的完成缓存一致性的工作。不要说一个读一个写,就是多个同时写都没问题。一个cpu读时总能读入最新的数据,不管它是在自己的cache中,还是在其它cpu的cache中,还是在内存中,这就是缓存一致性。

顺序一致性

所谓顺序一致性,说的则是与缓存一致性完全不同的概念,虽然它们都是处理器发展的产物。因为编译器的技术不断发展,它可能为了优化你的代码,而将某些操作的顺序更改执行。处理器中也早就有了多发射、乱序执行的概念。这样的结果,就是实际执行的指令顺序会与编程时代码的执行顺序略有不同。这在单处理器下当然没什么,毕竟只要自己的代码不过问,就没人过问,编译器和处理器就是在保证自己的代码发现不了的情况下打乱执行顺序的。但多处理器不是这样,可能一个处理器上指令的完成顺序,会对其它处理器上执行的代码造成很大影响。所以就有了顺序一致性的概念,即保证一个处理器上线程的执行顺序,在其它的处理器上的线程看来,都是一样的。这个问题的解决不是光靠处理器或者编译器就能解决的,需要软件的干预。

内存屏障

软件干预的方式也非常简单,那就是插入内存屏障(memory barrier)。其实内存屏障这个词,是由搞处理器的人造的,弄得我们很不好理解。内存屏障,很容易让我们串到缓存一致性去,乃至怀疑是否这样做才能让其它cpu看到被修改过的cache,这样想就错了。所谓内存屏障,从处理器角度来说,是用来串行化读写操作的,从软件角度来讲,就是用来解决顺序一致性问题的。编译器不是要打乱代码执行顺序吗,处理器不是要乱序执行吗,你插入一个内存屏障,就相当于告诉编译器,屏障前后的指令顺序不能颠倒,告诉处理器,只有等屏障前的指令执行完了,屏障后的指令才能开始执行。当然,内存屏障能阻挡编译器乱来,但处理器还是有办法。处理器中不是有多发射、乱序执行、顺序完成的概念吗,它在内存屏障时只要保证前面指令的读写操作,一定在后面指令的读写操作完成之前完成,就可以了。所以内存屏障才会对应有读屏障、写屏障和读写屏障三类。如x86之前保证写操作都是顺序完成的,所以不需要写屏障,但现在也有部分ia32处理器的写操作变成乱序完成,所以也需要写屏障。