.NET线程安全缓存结果

时间:2010-11-23 12:09:26

标签: .net multithreading

我在C#中有以下内容:

private double _x;
private bool _xCalculated;

private double GetX() {
    if (!_xCalculated) {
        _x = ... // some relatively expensive calculation
        _xCalculated = true;
    }

    return _x;
}

我的问题是,这是线程安全的吗?据我所知,最糟糕的结果是两个或多个线程同时进入此方法并多次计算_x,但对于此类的任何实例,结果保证相同,这不是一个特别大的问题。

我对此的理解是否正确?

3 个答案:

答案 0 :(得分:6)

一些观察结果:

  1. 加入double的商店可能不是原子的
  2. 对bool的写入应该是原子的
  3. 取决于CPU架构,可能会重新排序内存操作
  4. 如果没有重新排序,则代码应该正常工作
  5. 虽然我认为x86 memory ordering guarantees使这个安全,但我并不完全确定。最近.net的内存排序保证已得到加强(我认为在.net 4中)以匹配x86的保证。

    Memory Model in .net
    More on memory ordering
    这表明商店没有在.net中重新排序,我认为这意味着您的代码是安全的。但无锁编程很难,所以我可能会忽略一些微妙的问题。也许if子句中的读取可能会导致问题。

    我建议不要使用此代码,除非您是线程专家并且确实需要性能。否则只需使用像锁一样更明确的东西。如果他们没有参与竞争,锁定并不昂贵。

答案 1 :(得分:2)

它不是线程安全的。是的,你的理解是正确的。您可以使用lock()语句使其成为线程安全的。

http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.71).aspx

private object objLock = new object();
private double GetX() {
    lock(objLock) {
        if (!_xCalculated) { 
            _x = ... // some relatively expensive calculation 
            _xCalculated = true; 
        } 
    }
    return _x; 
} 

答案 2 :(得分:1)

这取决于平台,我不认为按照其规范使用.NET内存模型是安全的,但我认为在当前的Microsoft CLR上它是可以的。问题在于允许CPU 重新排序内存写入的范围。

有人可以提供规范的详细链接......