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

类SimpleThing
公开X作为整数
子新增(ByVal值作为整数)
X =值
结束子
末级
类ConcurrencyTest
Dim Thing1作为新的SimpleThing(5)
Dim Thing2作为新的SimpleThing(0)
Dim ThingRef为SimpleThing = Thing1
Dim ThingVal1,ThingVal2为整数
子Proc1()
Thing2.X = 5
Threading.Thread.MemoryBarrier()
ThingRef = Thing2
结束子
子Proc2()
ThingVal1 = Thing2.X
ThingVal2 = ThingRef.X
结束子
末级

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

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

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

最佳答案

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

-1。广告代码示例:

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

-2。广告IA64与x86 / x64:

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

-3。广告不可变:

如果您真的只是阅读并且它确实是一成不变的,那么它是安全的。

-4。广告单核:

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

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

10-07 13:21
查看更多