C# 易变双精度

C# 易变双精度,c#,.net,volatile,C#,.net,Volatile,由于只有引用类型和一些原语(包括float,但不是double,我不确定为什么,我很高兴听到为什么)可以声明为volatile,如果我在类中包装double,然后将其声明为volatile(如下所示),double属性是否会像任何其他volatile一样是“读写”线程安全的,还是我应该继续关注锁定 public class MyThreadedClass { volatile VolatileDouble voldub; } public class VolatileDouble {

由于只有引用类型和一些原语(包括float,但不是double,我不确定为什么,我很高兴听到为什么)可以声明为volatile,如果我在类中包装double,然后将其声明为volatile(如下所示),double属性是否会像任何其他volatile一样是“读写”线程安全的,还是我应该继续关注锁定

public class MyThreadedClass
{
    volatile VolatileDouble voldub;
}

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

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

对于您当前的答案,只有引用被视为不稳定的。这意味着内存模型将确保它始终使用最新的引用,但它仍然可以使用过时的值


如果我是你的话,我会选择锁定,但另一种选择是使用long并对long执行操作,同时使用and。您可以将其封装在
VolatileDouble
结构中。(我可能会把它变成一个结构而不是一个类。)

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

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; }
}
公共类MyThreadedClass
{
挥发性箱volDouble=123.45;
}
公共类框,其中T:struct
{
私有只读T值;
公用框(T值){this.value=value;}
公共T值{get{return Value;}}
//显式为空是一个问题。。。
公共静态显式运算符T(Box){
返回box.value;}
公共静态隐式运算符T?(框){
返回框==null?新T?():新T?(box.value);}
公共静态隐式运算符框(T值){
返回新框(值);}
公共静态隐式运算符框(T?值){
return value.HasValue?新框(value.value):null;}
}

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

您只是声明引用是可变的,而不是实例,因此这不会解决问题

易变的文档有点误导

当msdn文档说它使用最新的值时,这意味着什么???我确信,在一个简单的值中,这不会导致混淆,但是引用呢,因为Brian Rasmussen,您只是在谈论ref,而不是实际的实例(以及有趣的数据)


从我的观点来看,使用volatile不是一个好主意,我会选择锁,无论如何,本文可能会帮助您:

有点怀疑只有引用是volatile的,因此问题就来了。感谢您的确认如果他确保VolatileDouble是不变的,那么他就不会有问题,对吗?还感谢联锁和位转换器的建议,激发了一种全新的thought@Jonathan:是的,我相信在这种情况下是可以的-至少使用.NET 2.0内存模型,它比ECMA内存模型稍微强一点。很抱歉来晚了,但实际上它本质上是一个C#规范,它规定只有在大小为4或更小的类型上才能保证原子读/写。CIL在指针大小或更小的情况下(即x86上为4字节,x86_64上为8字节(看着你,加倍))更能保证原子r/w。编译器从C#编译到CIL,因此它无法知道处理器将是什么。谜题的最后一个部分是,只有保证了原子r/w操作的类型才能被删除。123.45f;如果你没有指出,我就不会注意到;)我怀疑是这样,因此提出了这个问题,谢谢你的确认