2017-03-07 64 views
2

我試圖追查一個我認爲可能與應用程序多線程相關的錯誤。我簡化了下面的代碼:從外部函數鎖定和ref值

class Outer { 
    private static int count; 

    //this function is called from multiple threads in quick succession 
    public void DoFoo() { 
    Inner.Increment(ref count); 
    } 
} 

class Inner { 
    private readonly static object mLock = new object(); 
    public static string Increment(ref count) { 
    lock (mLock) (
     if (count > 1000) 
     count = 0; 
     count++; 
    } 
    return count.ToString(); 
    } 
} 

鎖定可以保證以這種方式傳遞的變量的安全嗎?有沒有任何複製計數正在進行,似乎並不明顯,可能會破壞記憶安全?我在想它可能會返回一個新的int值,並在方法末尾執行賦值操作。除此之外,我的理解是鎖定部分可以處理任何緩存問題。

將問題買給我們注意的錯誤看起來是一個陳舊的count版本的線程之一。

回答

2

這裏的問題是,寫在你的代碼中的一些其他線程可以直接讀取Outer.count當它是== 0,因爲你可以訪問Outer.count,而沒有首先獲得一個鎖(通常,count只能前首先爲0來電Inner.Increment,從此只能有1和1001)之間的值

無鎖可以用這種方式來完成:

class Inner 
{ 
    public static string Increment(ref int count) 
    { 
     while (true) 
     { 
      int original = count; 
      int next = original; 

      if (next > 1000) 
      { 
       next = 0; 
      } 

      next++; 

      if (Interlocked.CompareExchange(ref count, next, original) == original) 
      { 
       return next.ToString(); 
      } 
     } 
    } 
} 

我計算next值,並使用它(通過Interlocked.CompareExchange ) 只有我在此期間,f count沒有變化。

+0

這就是我當時的想法,但是當鎖定語句被輸入(因爲它是一個引用)或者它會堅持陳舊值時它會得到最新值嗎? – flukus

+0

@flukus看看我修改後的代碼。 – xanatos

+0

這樣可以解決陳舊價值從外部傳入的問題嗎? – flukus

相關問題