Val*_*zub 7 .net concurrency volatile memory-model
public class TestHashRace
{
private int cachedHash = 0;
private readonly object value;
public object Value
{
get { return value; }
}
public TestHashRace(object value)
{
this.value = value;
}
public override int GetHashCode()
{
if (cachedHash == 0) {
cachedHash = value.GetHashCode();
}
return cachedHash;
}
//Equals isn't part of the question, but since comments request it, here we go:
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((TestHashRace) obj);
}
protected bool Equals(TestHashRace other)
{
return Equals(value, other.value);
}
}
Run Code Online (Sandbox Code Playgroud)
这是简单的测试类.
我们保证GetHashCode
会永远返回相同的价值吗?如果我们是,有人可以指出一些给我们这种保证的参考资料吗?
我们不担心它是否多次计算我们的值的哈希码,我们只是想确保返回的值总是相同的.
我们的类必须是不可变的,而cachedHash
字段是可变的.由于性能原因,Field不能变化(我们在这里质疑这个问题和优化的整个想法).价值是不可改变的.它必须是线程安全的.
对于某些特定值,当它为0时,我们可以使用潜在的哈希码重新计算.我们不希望使用可空类型或为内存原因添加其他字段(如果我们只存储1个int,则使用更少的内存),因此它必须是一个int字段来处理哈希码问题.
我们是否保证GetHashCode将始终返回相同的值?
不可以.保证仅适用于value
具有正确实现GetHashCode
方法的不可变对象.可变对象在其内容发生变异时可能会更改其哈希码(这就是为什么不应将可变对象用作哈希键的原因).
即使它TestHashRace
本身是不可变的,也是如此,因为你可以这样做:
var evil = new StringBuilder("hello");
var thr = new TestHashRace(evil);
RunConcurrentCode(thr);
evil.Append(", world!");
Run Code Online (Sandbox Code Playgroud)
如果多个线程同时RunConcurrentCode
启动对thr
s 的调用GetHashCode
,然后在不同的侧面完成Append
,则返回的数字value.GetHashCode
可能不同.
[ 编辑: ]值是不可变的
然后,为保证持有所要求的唯一的事情就是value
的GetHashCode
正确实施,即不使用随机的东西等.
注:由于零是哈希码合法的值,你的代码可能会重复调用value
的GetHashCode
时候实际的代码是零.解决这个问题的一种方法是使用nullable cachedHash
:
int? cachedHash;
...
public override int GetHashCode() {
return cachedHash ?? (cachedHash = value.GetHashCode());
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
198 次 |
最近记录: |