2010-11-23 79 views
6

我有類似的東西在C#中的以下內容:.NET線程安全的緩存結果

private double _x; 
private bool _xCalculated; 

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

    return _x; 
} 

我的問題是,這是線程安全的?據我所知,最糟糕的結果是兩個或更多線程同時輸入此方法並多次計算_x,但結果對於此類的任何實例都保證是相同的,所以這不是一個特別巨大的問題。

我的理解是否正確?

回答

6

幾個意見:

  1. 商店到雙可能不是原子
  2. 爲BOOL寫應該是原子的
  3. 根據CPU架構的不同,內存操作可能會重新排序
  4. 如果不發生重新排序,代碼應該工作

雖然我認爲x86 memory ordering guarantees使這個安全,我不完全確定這一點。 .net的內存命令保證最近被加強了(我想在.net 4中)以配合x86的保證。

Memory Model in .net
More on memory ordering
此規定,商店不能在.NET我認爲重新排序意味着你的代碼是安全的。但無鎖編程很難,所以我可能會忽略一些微妙的問題。 if語句中的讀取可能會導致問題。

我建議不要使用這段代碼,除非你是一個線程專家,並且確實需要性能。否則,只需使用更像鎖的更明確的東西。如果他們沒有競爭,鎖定並不昂貴。

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

請避免使用鎖(此)。最好鎖定一個私人對象lockObject = new object();見http://www.toolazy.me.uk/template.php?content=lock(this)_causes_deadlocks.xml – 2010-11-23 12:26:43

+0

並聲明不安全的是一個大膽的索賠,沒有給出這個說法的一些理由。 – CodesInChaos 2010-11-23 12:35:40

1

這取決於平臺上,我不認爲這是與.NET的內存模型按照其規範安全,但我認爲這是對當前微軟CLR確定。問題是CPU允許的範圍重新排序內存寫入

可有人請拿出來規範詳細的鏈接...