3

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

类 SimpleThing
    公共 X 作为整数
    Sub New(ByVal value As Integer)
        X = 价值
    结束子
结束类
类并发测试
    Dim Thing1 作为新的 SimpleThing(5)
    Dim Thing2 作为新的 SimpleThing(0)
    将 ThingRef 调暗为 SimpleThing = Thing1
    将 ThingVal1、ThingVal2 调暗为整数
    子程序1()
        事物2.X = 5
        Threading.Thread.MemoryBarrier()
        ThingRef = Thing2
    结束子
    子进程2()
        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 之类的单个内核上,否则无法保证正确运行)?

4

1 回答 1

0

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

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

CLR 自 2.0 起已订购商店。这意味着您的 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 没有提供这个关键字。

于 2011-01-15T19:26:06.680 回答