解除引用字段时是否需要内存屏障(.net x86或x64)?

时间:2011-01-14 23:25:34

标签: vb.net x86 64-bit memory-model memory-barriers

在如下代码中,如果Proc1和Proc2在不同的处理器上同时执行,ThingVal2是否可以获得5以外的值(例如零)?

Class SimpleThing
    Public X As Integer
    Sub New(ByVal value As Integer)
        X = value
    End Sub
End Class
Class ConcurrencyTest
    Dim Thing1 As New SimpleThing(5)
    Dim Thing2 As New SimpleThing(0)
    Dim ThingRef As SimpleThing = Thing1
    Dim ThingVal1, ThingVal2 As Integer
    Sub Proc1()
        Thing2.X = 5
        Threading.Thread.MemoryBarrier()
        ThingRef = Thing2
    End Sub
    Sub Proc2()
        ThingVal1 = Thing2.X
        ThingVal2 = ThingRef.X
    End Sub
End Class

我知道在像IA64这样的弱模型中,Proc2可能会看到ThingRef已经发生了变化但是没有看到Thing2的字段X已经这样做了。在x86或x64上运行的.Net应用程序是否存在风险?如果Proc1创建了SimpleThing的新实例,将其X字段设置为5,然后将ThingRef设置为指向它,这是否足以避免危险,或者是否可能在缓存行上分配新事物与Proc2线程访问过的其他东西共享了吗?

具有多线程代码的常见范例是构造一个不可变对象并设置一个指向它的可变引用(可能使用Interlocked.CompareExchange)。在x86 / x64下是否始终安全地读取不可变类型而不考虑线程,或者是否会导致问题?如果是后者,vb.net中保证可靠行为的首选方式是什么?

此外,是否有任何方法可以指定代码必须以不会发生此类问题的方式运行(例如,在IA64之类的内容上限制执行,否则无法保证正确的操作)?

1 个答案:

答案 0 :(得分:0)

好的,你提出了很多问题。我会尽力回答我所知道的事情。

-1。广告您的代码示例:

CLR自2.0起订购商店。这意味着你的ThingVal在x86 / x64上总是5。当然。我没有在真正的IA64上尝试过它,但它在IA64上应该也能正常工作,因为CLR应该确保所有平台上的有序写入,并且对于你的简单示例应该足够了。

-2。 ad IA64 vs x86 / x64:

x86 / x64具有不同的内存语义,并且没有像IA64那样的风险。这里唯一可能的问题是你实际上使用的是更高级别的语言,如果它使用了优化编译器(比如C ++那样),你就无法预测任何事情而不知道编译器如何进行优化。未记载:VB不执行任何全局优化等,因此您的代码应该是安全的。

-3。 ad immutable:

如果你真的只是阅读它并且它确实是不可改变的,那么它是安全的。

-4。 ad single core:

您可以设置线程关联。它是每个线程的标准属性,并定义线程可以在哪些CPU上运行。 (.net的线程相关性设置直接改变了操作系统中的亲和力。)但它会使你的程序运行缓慢。

此外,您可以切换到C#并使用 volatile 关键字。它将帮助您更轻松地生活,因为它会对所有CPU立即看到的volatile变量进行任何更改,从而解决您在此处提出的所有可能问题。不幸的是,VB没有提供这个关键字。