给出这样的结构:
struct foo {
atomic_int refcount; /* atomic access */
char* bar1; /* read-only */
char* bar2; /* read-only */
};
严格地说:是否有必要使用atomic_intptr_t
用于bar1
和bar2
来保证非原子变量的跨线程可见性,因为我使用了正确的获取/释放语义?
答案 0 :(得分:3)
抽象地说,对原子变量的获取/释放操作之间发生的任何内存操作都会表现得就像你已经获得并发布了一个抽象的互斥类型(POSIX,WinAPI等),因为无论如何通常都会实现这些操作。 。原子操作和定义的内存模型的主要目标是定义如何在原子访问周围对非原子内存访问进行排序。所以他们不应该是原子的。
如果你从不写指针,那么在初始化结构之后你只需要一个内存屏障,以确保初始值在其他线程中可见。如果在你的关键部分中你改变了指针引用的内容,那么获取/释放语义将确保这些更改也变得可见。
有用的阅读(我不确定C11和C ++ 11的内存模型之间有什么区别): http://en.cppreference.com/w/cpp/atomic/memory_order
http://bartoszmilewski.com/2008/12/01/c-atomics-and-memory-ordering/
编辑:添加了更好的链接。
答案 1 :(得分:1)
要迂腐(在讨论内存模型时这是一件好事),没有任何事情要求将永远变更为其他线程可见。您可以保证在同步点发生的事情:如果您的获取读取读取某个新值,然后,您可以保证线程的所有效果使用release-write来编写在该线程中写入之前出现并且可见的新值。但是你实际上没有保证 你的获取阅读将会读取新值。
C ++ 11对此更加具体,并且包含一个“注意”,“操作将在有限的时间内对所有其他线程可见”(C ++ 11,1.10 / 25),但我在C11中没有看到任何类似的陈述。
(我实际上在Herb Sutter's atomic talk上发布了对此效果的评论。)