10

因为只有引用类型和一些原语(包括浮点数,但不是双精度数,我不确定原因,我很高兴听到为什么)可以声明为易失性,如果我在一个类中包装一个双精度然后声明它作为易失性(如下),双重属性是否像任何其他易失性一样是“读写”线程安全的,还是我仍然应该关注锁定?

public class MyThreadedClass
{
    volatile VolatileDouble voldub;
}

public class VolatileDouble
{
    public double Double { get; set; }
}
4

4 回答 4

18

不能将 double 声明为 volatile 的原因:它是 64 位,这使得它超过了 x86 上的字长,如果我没记错的话,这可以防止它在 CLI 中被声明为 volatile。

根据您当前的答案,只有参考被视为易失性。这意味着内存模型将确保它始终使用最新的引用,但它仍然可以使用陈旧的值。

如果我是你,我会选择锁定,但另一种选择是使用Interlocked.ReadInterlocked.Exchange作用于多头,与BitConverter.Int64BitsToDoubleand结合使用BitConverter.DoubleToInt64Bits。您可以将其封装在一个VolatileDouble结构中。(我可能会把它变成一个结构而不是一个类。)

于 2009-02-10T10:15:10.477 回答
5

要像上面那样工作,你需要让它不可变(没有设置器)——为了方便起见,可能使用一些隐式转换运算符。否则,人们可以在不更改(易失性)引用的情况下更改值。

public class MyThreadedClass
{
    volatile Box<double> volDouble = 123.45;
}

public class Box<T> where T : struct
{
    private readonly T value;
    public Box(T value) { this.value = value; }
    public T Value {get {return value;}}

    // explicit as nulls are a problem...
    public static explicit operator T(Box<T> box) {
        return box.value; }
    public static implicit operator T?(Box<T> box) {
        return box == null ? new T?() : new T?(box.value); }
    public static implicit operator Box<T>(T value) {
        return new Box<T>(value); }
    public static implicit operator Box<T>(T? value) {
        return value.HasValue ? new Box<T>(value.Value) : null; }
}

除此之外 - 锁定将是最好的选择。

于 2009-02-10T10:15:35.703 回答
3

您只是声明引用是 volatile 而不是实例,所以这不会解决问题。

于 2009-02-10T10:15:38.917 回答
0

不稳定的文档有些误导...

当 msdn 文档说它使用最新值时,这是什么意思???我敢肯定,在一个简单的值中,这不会导致混淆,但是引用呢,就像 Brian Rasmussen 一样,您只是在谈论 ref 而不是实际实例(因此是有趣的数据)。

从我的角度来看,使用 volatile 不是一个好主意,我会去锁定,无论如何这篇文章可能会帮助你: http: //www.bluebytesoftware.com/blog/PermaLink,guid,dd3aff8a-7f8d-4de6- a2e7-d199662b68f4.aspx

于 2009-02-10T11:26:53.073 回答