如何使 T 类型的字段可变?
How can I make a field of type T volatile?
我试图将一堆重复代码整合到具有以下结构的实用程序中 class:
public class Shared<T>
{
private volatile T _value;
public object Lock { get; private set; }
public T Value
{
get { lock (Lock) return _value; }
set { lock (Lock) _value = value; }
}
public Shared(T startingValue)
{
_value = startingValue;
Lock = new object();
}
public Shared()
: this(default(T))
{
}
}
但是,C#不会让我。文档指出 T
必须是引用类型或原语之一(int、bool 等)。我唯一关心的类型是引用类型和布尔值。显然,我不能使用无界类型 T
。有什么办法可以使这项工作吗?甚至可以为此添加约束以使其作为 Shared<bool>
工作吗?我什至不允许将其他结构类型标记为易变的。 :(
如果无法将其标记为易失性,我是否有其他保证在多个线程尝试读取该值时它不会被优化掉?
您可以轻松地将泛型类型限制为仅引用...
public class Shared<T> where T : class
...但是也没有办法将其限制为 bool。 class 非常小,因此您可以为布尔类型创建一个特定的实现。
但是...
你在读取和写入值时的锁定完全没有用。对象引用的 read/write 在 .NET 中是原子的,因此不需要锁。它只是减慢了速度。 (布尔值被实现为一个 4 字节整数,它们也是原子的,所以你的布尔版本也不需要它)
volatile 关键字意味着每次读取值时都会确保从内存中再次读取该值。这解决了值可能缓存在寄存器或 L1/L2 缓存中的问题。在这种情况下,后续访问将是 register/cached 值,即使另一个 CPU 可能已经在主内存中更改了它。所以你的volatile会阻止值被缓存到一个寄存器中,保证每次读取都和主存一致。
(这不是特定于 volatile
问题,而是针对此类情况的可能的一般解决方法。)
您可以让您的 class 实现一个接口(例如,IShared<T>
)。通过通用工厂方法构造它的实例。然后您可以提供多个实现。
对于引用类型,您可以 return 个您已有的 class 实例,限制为 T : class
。对于原始类型,您可以 return 实现 IShared<bool>
、IShared<int>
等的专用非泛型 classes 的实例
我试图将一堆重复代码整合到具有以下结构的实用程序中 class:
public class Shared<T>
{
private volatile T _value;
public object Lock { get; private set; }
public T Value
{
get { lock (Lock) return _value; }
set { lock (Lock) _value = value; }
}
public Shared(T startingValue)
{
_value = startingValue;
Lock = new object();
}
public Shared()
: this(default(T))
{
}
}
但是,C#不会让我。文档指出 T
必须是引用类型或原语之一(int、bool 等)。我唯一关心的类型是引用类型和布尔值。显然,我不能使用无界类型 T
。有什么办法可以使这项工作吗?甚至可以为此添加约束以使其作为 Shared<bool>
工作吗?我什至不允许将其他结构类型标记为易变的。 :(
如果无法将其标记为易失性,我是否有其他保证在多个线程尝试读取该值时它不会被优化掉?
您可以轻松地将泛型类型限制为仅引用...
public class Shared<T> where T : class
...但是也没有办法将其限制为 bool。 class 非常小,因此您可以为布尔类型创建一个特定的实现。
但是...
你在读取和写入值时的锁定完全没有用。对象引用的 read/write 在 .NET 中是原子的,因此不需要锁。它只是减慢了速度。 (布尔值被实现为一个 4 字节整数,它们也是原子的,所以你的布尔版本也不需要它)
volatile 关键字意味着每次读取值时都会确保从内存中再次读取该值。这解决了值可能缓存在寄存器或 L1/L2 缓存中的问题。在这种情况下,后续访问将是 register/cached 值,即使另一个 CPU 可能已经在主内存中更改了它。所以你的volatile会阻止值被缓存到一个寄存器中,保证每次读取都和主存一致。
(这不是特定于 volatile
问题,而是针对此类情况的可能的一般解决方法。)
您可以让您的 class 实现一个接口(例如,IShared<T>
)。通过通用工厂方法构造它的实例。然后您可以提供多个实现。
对于引用类型,您可以 return 个您已有的 class 实例,限制为 T : class
。对于原始类型,您可以 return 实现 IShared<bool>
、IShared<int>
等的专用非泛型 classes 的实例