内存屏障(Memory Barrier)是在计算机体系结构中使用的一种同步机制,用于确保在多线程或多核处理器环境中,对共享内存的操作按照预期顺序进行。它们通过强制在特定点执行一些指令来规定内存访问的顺序,并防止内存乱序执行带来的不一致性问题。
内存屏障分为两种类型:读屏障(Read Barrier)和写屏障(Write Barrier)。
读屏障用于确保在读操作之前,所有该读操作之前的写操作已经完成。它可以防止指令乱序执行,保证读取到的数据是最新的。
写屏障用于确保在写操作之前,所有该写操作之前的写操作和读操作都已经完成。它可以防止指令乱序执行,保证写入的数据不会被其他操作覆盖或丢失。
内存屏障的使用能够解决多线程或多核处理器中的原子性、可见性和有序性等问题,确保程序的正确性和一致性。在编写并发程序时,合理地使用内存屏障可以提高程序的性能和正确性。
void foo(void)
{a = 1;smp_mb();b = 1;
}void bar(void)
{while (b == 0) continue;assert(a == 1);
}
https://www.kernel.org/doc/Documentation/memory-barriers.txthttps://www.kernel.org/doc/Documentation/memory-barriers.txt
Consider the following abstract model of the system:: :: :: :+-------+ : +--------+ : +-------+| | : | | : | || | : | | : | || CPU 1 |<----->| Memory |<----->| CPU 2 || | : | | : | || | : | | : | |+-------+ : +--------+ : +-------+^ : ^ : ^| : | : || : | : || : v : || : +--------+ : || : | | : || : | | : |+---------->| Device |<----------+: | | :: | | :: +--------+ :: :
(memory barriers logically act on the dotted line in the following diagram):<--- CPU ---> : <----------- Memory ----------->:+--------+ +--------+ : +--------+ +-----------+| | | | : | | | | +--------+| CPU | | Memory | : | CPU | | | | || Core |--->| Access |----->| Cache |<-->| | | || | | Queue | : | | | |--->| Memory || | | | : | | | | | |+--------+ +--------+ : +--------+ | | | |: | Cache | +--------+: | Coherency |: | Mechanism | +--------++--------+ +--------+ : +--------+ | | | || | | | : | | | | | || CPU | | Memory | : | CPU | | |--->| Device || Core |--->| Access |----->| Cache |<-->| | | || | | Queue | : | | | | | || | | | : | | | | +--------++--------+ +--------+ : +--------+ +-----------+::
Cache 一致性问题出现的原因是在一个多处理器系统中,每个处理器核心都有独占的Cache 系统(比如一级 Cache 和二级 Cache),而导致一个内存块在系统中同时可能有多个备份,从而引起访问时的不一致性问题。Cache 一致性问题的根源是因为存在多个处理器独占的 Cache,而不是多个处理器。它的限制条件比较多:多核,独占 Cache,Cache 写策略。当其中任一个条件不满足时便不存在cache一致性问题。
read: 包含要读取的CACHE-LINE的物理地址
read response: 包含READ请求的数据,要么由内存满足要么由cache满足
invalidate: 包含要invalidate的cache-line的物理地址,所有其他cache必须移除相应的数据项
invalidate ack: 回复消息
read invalidate: 包含要读取的cache-line的物理地址,同时使其他cache移除该数据。需要read response和invalidate ack消息
writeback:包含要写回的数据和地址,该状态将处于modified状态的lines写回内存,为其他数据腾出空间
void foo(void)
{a = 1;smp_mb();b = 1;
}
smp_mb()指令可以迫使CPU在进行后续store操作前刷新store-buffer。以上面的程序为例,增加memory barrier之后,就可以保证在执行b=1的时候CPU0-store-buffer中的a已经刷新到cache中了,此时CPU1-cache中的a 必然已经标记为invalid。对于CPU1中执行的代码,则可以保证当b==0为假时,a已经不在CPU1-cache中,从而必须从CPU0- cache传递,得到新值“1”