m : modified 修改

e : exlusive 独占

s : shared 共享

i : invalid 无效

各种状态的转换从网上摘抄一段

cpu核之间通信的消息包括读消息,以及读消息的响应消息。使无效消息,以及使无效消息的响应消息。当运行在某个cpu核的线程准备读取某个cache line的内容时,如果状态处于M,E,S,直接读取即可。如果状态处于I,则需要向其他cpu核广播读消息,在接受到其他cpu核的读响应后,更新cache line,并将状态设置为S。而当线程准备写入某个cache line时,如果处于M状态,直接写入。如果处于E状态,写入并将cache line状态改为M。如果处于S,则需要向其他cpu核广播使无效消息,并进入E状态,写入修改,后进入M状态。如果处于I,则需要向其他cpu核广播读消息和使无效消息,在收集到读响应后,更新cache line。在收集到使无效响应后,进入E状态,写入修改,后进入M状态。

缓存一致性协议使得多核cpu的共享变量之间的改变可以相互可见,按理说可以了。

但是在cpu和L1L2的cacheLine之间还有storebuffer这样的缓冲,这就需要volatile出场了。

volatile修饰变量在汇编的时候会多出 lock前缀,这个前缀在“写变量”这个过程中有两个作用:

1、禁止指令重排序

2、将当前cpu的L1之前的缓冲都刷新到L1中

 

i++的问题是写更新丢失的问题,跟现在说的没关系,要用cas解决。

cas其实不是原子性操作,要读一次,再写一次。但是可以用MESI实现原子性:读一次发现是目标值,写的时候判断是不是I就可以。mesi实现其他原子性操作也是这个思路。