13

在下面的代码中将read1始终等于read2,提供的属性Flag可以从其他线程更改吗?这里担心的是Flag可能会被内联。

private bool Flag {get; set;}

public void MultithreadedMethod()
{
    var read1 = Flag;

    /* some more code */

    var read2 = Flag;    
}

UPD:其他一些线程可能会在执行Flag期间更改 ' 值。/* some more code */在这种情况下read1应该不同于read2. 会一直这样吗?尽管事实在读取之间发生了变化,但内联不会将属性变成一个非易失性字段,这将导致read1等于?read2Flag

4

6 回答 6

17

不,属性不是volatile

虽然我无法为您的初始场景获得令人满意的演示,但这种替代方法应该很好地证明了该陈述:

class Program
{
    public bool Flag { get; set; }

    public void VolatilityTest()
    {
        bool work = false;
        while (!Flag)
        {
            work = !work; // fake work simulation
        }
    }

    static void Main(string[] args)
    {
        Program p = new Program();
        var t = new Thread(p.VolatilityTest);
        t.Start();
        Thread.Sleep(1000);
        p.Flag = true;
        t.Join();
    }
}

在发布模式下构建它会使程序死锁,因此证明它Flag没有易失性行为(即它在读取之间得到“优化”)。

替换public bool Flag { get; set; }public volatile bool Flag;将使程序正确终止。

于 2012-05-29T10:28:05.147 回答
3

是的,它可以自然地改变。

即使在提供的代码中,也不能保证read1等于read2.

考虑到同时/* some more code */执行,Flag可能会受到其他线程的影响。

编辑

and的相等性read1read2内联与否无关,Flag是 a bool,所以它是一个值类型。所以

  • var read1 = Flag;//假设read1 TRUE
  • Flag = False
  • var read2 = Flag;//read2 为 FALSE,但 read1 仍为 TRUE

这在多线程环境中也有效,因为您在值类型上进行操作。

如果这不是您要的,请澄清。

于 2012-05-29T09:25:14.383 回答
1

如果可以从其他线程更改 Flag,则不能保证 read1 和 read2 会相同。您必须在代码周围使用监视器/互斥锁,并确保标志设置器也尊重该互斥锁。

于 2012-05-29T09:26:09.700 回答
1

总结其他回复,在这种情况下,无法预测代码执行后两个变量的值会发生什么。既因为 CLR 和编译器对我们来说很大程度上是黑匣子,也因为任何关于竞争条件结果的预测实际上都是一场赌博,在某些时候肯定是错误的。

无论如何,您不能在多线程环境中编写此类代码。

于 2012-05-29T09:58:21.087 回答
1

汽车产业缺乏波动性是令人失望的。我发现当使用带有 [StructLayout(LayoutKind.Sequential, Pack = 4)] 和 Marshal.PtrToStructure 的结构时,如果使用自动属性,字节布局不会按预期保留。我所做的是使用私有支持字段并将属性放在最后。

于 2012-10-23T09:59:35.010 回答
-1

根据文档

volatile 关键字表示一个字段可以在程序中被操作系统、硬件或并发执行的线程等东西修改。... 使用 volatile 修饰符可确保一个线程检索另一个线程写入的最新值。

于 2012-05-29T09:30:40.157 回答