我试图将一堆重复代码合并到具有以下结构的实用程序类中:
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等)。我关心的唯一类型是引用类型和bools。显然,我不能使用无界类型T
。有没有办法让这项工作成功?甚至可以为此添加约束以使其作为Shared<bool>
工作吗?我甚至不允许将其他结构类型标记为volatile。 :(
如果没有可能的方法将其标记为volatile,我是否还有其他保证,当多个线程尝试读取此值时,它不会被优化掉?
答案 0 :(得分:4)
您可以轻松地将泛型类型限制为仅引用...
public class Shared<T> where T : class
...但是也无法将此限制为 bool 。该类非常小,因此您可以为布尔类型创建特定的实现。
<强> BUT ... 强>
在读取和写入值期间锁定完全没用。对象引用的读/写在.NET中是原子的,因此不需要锁。它只会减慢速度。 (布尔值实现为4字节整数,它们也是原子的,因此布尔版本也不需要它)
volatile关键字意味着每次读取值时,它都会确保它从内存中再次读取值。这解决了值可能缓存在寄存器或L1 / L2缓存中的问题。在这种情况下,后续访问将是寄存器/缓存值,即使另一个CPU可能已在主存储器中更改它。所以你的volatile会阻止缓存在寄存器中的值,并确保每次读取都与主存储器一致。
答案 1 :(得分:1)
(这不是针对volatile
问题的具体问题,而是针对此类案例的可能的一般解决方法。)
您可以让您的类实现一个接口(例如,IShared<T>
)。通过通用工厂方法构造它的实例。然后,您可以提供多种实现。
对于引用类型,您可以返回已有类的实例,约束为T : class
。对于基本类型,您可以返回实现IShared<bool>
,IShared<int>
等的专用非泛型类的实例。