考虑以下证明存在错误共享的示例:
using type = std::atomic<std::int64_t>;
struct alignas(128) shared_t
{
type a;
type b;
} sh;
struct not_shared_t
{
alignas(128) type a;
alignas(128) type b;
} not_sh;
一个线程按步骤1递增a,另一个线程递增b。使用MSVC将增量编译为lock xadd,即使结果未使用。
对于一个将a和b分开的结构,not_shared_t在几秒钟内积累的值大约是shared_t
假设我们有以下情况:2 CPU、wtih写缓冲区和MESI作为缓存一致性协议。我们在CPU之间有一条共享缓存线:
CPU1缓存:|I|I|S|I|I|
CPU2缓存:|I|I|S|I|I|
现在,CPU1决定修改共享行。它将更改记录放入其写缓冲区,并向CPU2发送无效消息。CPU2接收到它并发送一个确认:
CPU1缓存:|I|I|S|I|I|,CPU1写缓冲区:change for the 3rd cache line
CPU2缓存:|I|I|I|I|I|
在接收到确认时,CPU1不需要刷新写缓冲区并将缓存行状态更改为M(修改),这是对的吗?如果不是,让我们走得更远。
假设现在CPU2想再次读
考虑到在ARMv8 CPU上出现这样的情况(尽管这可能也适用于许多其他CPU):
class abcxzy
{
// Pragma align to cacheline to ensure they exist on same line.
unit32_t atomic_data;
uint32_t data;
void foo()
{
volatile asm (
" ldr w0, [address of data]\n"
"# Do stuff with data in w0..."