天天看点

head_和tail_还有后面的变量中加添加了无意义的字段P0、P1和P2,因为head_和tail_频繁变化,目的是防

作者:从头开始自学java

head_ 和 tail_ 还有后面的变量中加添加了无意义的字段 P0、P1 和 P2 ,因为 head_ 和 tail_ 频繁变化,目的是防止出现前面讲过的伪共享导致性能下降问题。

构造函数中强制传入的队列大小(size)必须为 2 的幂数,目的是想用 & 而不是 % 取模,因为 & 比 % 快 2ns,最求极致性能。

Push 和 Pop 函数中读写操作是否需要增加内存屏障,读写操作可以抽象描述如下表格:

在读写操作乱序的 CPU 上可以出现上述情况,会导出线 Bug,解释一下:

当刚初始化的队列,队列还是空的,这时核心0 执行 Push 函数,同时核心1 执行 Pop 函数;

Push 里的条件(tail <= head ? tail + size_ <= head + 1 : tail <= head + 1)为 true,表示队列已经满了,所以生产失败,其实队列还是空的;

Pop 里的条件(tail == head_ || !valid_[tail])为 false,表示队列有数据,并且消费 tail 位置数据,实际上 tail 位置还没数据;

导致生产和消费都发生了错误。

解决办法是添加读写屏障(LoadStore barrier)

在 Arm 等乱序执行的平台上可以解决问题;幸好 x86-TSO 平台上读操作不能延后,也就不需要读写屏障,手动加了也是空操作(no-op)。

head_和tail_还有后面的变量中加添加了无意义的字段P0、P1和P2,因为head_和tail_频繁变化,目的是防
head_和tail_还有后面的变量中加添加了无意义的字段P0、P1和P2,因为head_和tail_频繁变化,目的是防
head_和tail_还有后面的变量中加添加了无意义的字段P0、P1和P2,因为head_和tail_频繁变化,目的是防
head_和tail_还有后面的变量中加添加了无意义的字段P0、P1和P2,因为head_和tail_频繁变化,目的是防
head_和tail_还有后面的变量中加添加了无意义的字段P0、P1和P2,因为head_和tail_频繁变化,目的是防

继续阅读