比方说,我有以下代码:C++内存排序一致性
void* p0 = nullptr;
void* p1 = alloc_some_data();
void f1() {
p0 = p1;
p1 = nullptr;
}
假设f1
上线1.运行是否有可能(离开代码,因为它是)另一个线程可能在某一时刻看到p0
和p1
作为nullptr
(如果编译器或硬件重新排序指令,比如第二次分配在第一次之前发生)?
我问这个的原因是因为我想实现一个垃圾收集器,我想知道是否需要使用原子指令访问GC线程中的指针(std::atomic
)。如果GC线程看到p0 == p1 == alloc_some_data()
则没有问题,但如果GC线程看到p0 == p1 == nullptr
,则会出现问题,因为它会将p1中以前的数据报告为无法访问,因为它显然是可访问的。
从我的理解来看,跟踪gc over ref counting的好处是避免锁(以refs为增量)。如果每个更新程序线程中的引用更新需要互斥锁,那么性能增益优先于ref计数?跟踪gc方法然后像lock参数计数方法一样使用锁膨胀代码路径(在mutator线程中),对吧?是否可以编写一个跟踪gc,其中的增变器线程可以用一个简单的MOV指令更新一个引用?任何人都可以指向一个方向(一篇文章或一本书...)吗? –
我不太了解垃圾回收评论。就我个人而言,我喜欢引用计数,因为内存尽快释放。某些操作系统提供的原子增量和减量指令比使用互斥锁要快得多。在这种情况下,引用计数会胜出。如果您使用的是Windows/Visual Studio,则可能需要查看Microsoft特定的“volatile”语义。 – paddy
@DaniloCarvalho:我对GC也不太熟悉,但很多非引用计数GC都是* stop-the-world * GC:环境将停止所有线程,执行GC(可能重定位对象和更新指针),然后让所有线程继续。 –