.net - 我们能保证通过数据竞争缓存哈希码能正常工作吗?

标签 .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);
    }
}

这是简单的测试类。

我们保证GetHashCode将始终返回相同的值?
如果是的话,有人可以指出一些可以为我们提供这种保证的引用资料吗?

如果它为我们的值计算哈希码不止一次,我们并不担心,我们只想确保返回的值始终相同。

我们的类必须是不可变的,而 cachedHash字段是可变的。出于性能原因,字段不能是 volatile (我们在这里质疑的这个问题和优化的整个想法)。值(value)是不可变的。而且它必须是线程安全的。

当某些特定值的哈希码为 0 时,我们可以接受潜在的哈希码重新计算。我们不想使用可空类型或出于内存原因添加额外的字段(如果我们只存储 1 个 int 则使用更少的内存),因此它必须是一个 int 字段来处理哈希码问题。

最佳答案

Are we guaranteed that GetHashCode will always return the same value?



不。该保证仅适用于不可变 value正确实现的对象 GetHashCode方法。当可变对象的内容发生变异时,可变对象可能会更改其哈希码(这就是为什么不应该将可变对象用作哈希键的原因)。

即使 TestHashRace 也是如此本身是不可变的,因为你可以这样做:
var evil = new StringBuilder("hello");
var thr = new TestHashRace(evil);
RunConcurrentCode(thr);
evil.Append(", world!");

如果 RunConcurrentCode 中有多个线程开始调用 thrGetHashCode同时,然后在Append的不同侧完成,从 value.GetHashCode 返回的数字可能不同。

[Edit:] Value is immutable



那么保证书唯一需要的就是valueGetHashCode正确实现,即不使用随机内容等。

注:由于零是哈希码的合法值,您的代码可能会重复调用 valueGetHashCode当实际代码为零时。解决此问题的一种方法是使用可为空的 cachedHash :
int? cachedHash;
...
public override int GetHashCode() {
    return cachedHash ?? (cachedHash = value.GetHashCode());
}

关于.net - 我们能保证通过数据竞争缓存哈希码能正常工作吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40792730/

相关文章:

java - 核心java中的原子问题

java - 为什么 Java 没有有效地利用我所有的 CPU 内核

java - Java中的 volatile 变量

c - 当有多个间接级别时如何解释 volatile

c# - 如何将数据表从 C# 传递到 SQL Server 存储过程

c# - 如何在 .Net 中实现 ConcurrentHashSet

c# - 如何在一个项目中使用两个不同的 Microsoft Interop 程序集?

c# - 正则表达式至少找到两个字符之一

Go-lang并行段运行速度比串行段慢

c - 仅在 ISR 中读取的变量的 volatile ?