2013-07-22 60 views
2

在致電Interlocked.Increment之後,檢查溢出的正確方法是什麼?如何在C#中的Interlocked.Increment之後檢查溢出?

我有一個ID生成器,在程序執行期間生成唯一的ID,目前我測試它的增量返回零。

public static class IdGenerator { 
    private static int _counter = 0; 

    public static uint GetNewId() { 
     uint newId = (uint)System.Threading.Interlocked.Increment(ref _counter); 
     if (newId == 0) { 
      throw new System.Exception("Whoops, ran out of identifiers"); 
     } 
     return newId; 
    } 
} 

鑑於相當大的數量,我每次運行生成的ID,它是不可能性(在一個非常大的輸入),其增加時_counter就會溢出,我想拋出一個excetption在這種情況下(崩潰儘早調試)。從Microsoft's documentation

摘錄:

該方法通過包裝處理溢出狀況:如果location = Int32.MaxValuelocation + 1 = Int32.MinValue。沒有例外被拋出。

+0

建議使用'long'

  • X2空間。 – SLaks

  • +0

    請注意'(uint)int.MinValue'拋出。 – SLaks

    +0

    @SLaks(你最近的評論)那麼,作爲一個文字的'(uint)int.MinValue'將不會被編譯。但是一個非const的變量或者表達式'int i = int.MinValue'會影響轉換'(uint)i''不會拋出通常的'unchecked'上下文。 –

    回答

    4

    只是檢查newId是否Int32.MinValue(鑄造uint前),並拋出一個異常。

    從增量獲得MinValue的唯一方法是通過溢出。

    +0

    如果兩個線程短暫遞增該值會怎麼樣? –

    +2

    @JeppeStigNielsen:然後其中一個會溢出,另一個不會。 「互鎖增量」的重點在於它是原子的;這不是問題。 – SLaks

    +0

    啊,當然,你告訴他檢查'Increment'的返回值,而不是'_counter'字段的實際值。那麼我同意你的看法。但他應該擺脫他對「uint」的轉換,或者其他什麼。 –

    0

    考慮使用unchecked

    public static class IdGenerator 
    { 
        private static int _counter; 
    
        public static uint GetNewId() 
        { 
         uint newId = unchecked ((uint) System.Threading.Interlocked.Increment(ref _counter)); 
         if (newId == 0) 
         { 
          throw new System.Exception("Whoops, ran out of identifiers"); 
         } 
         return newId; 
        } 
    } 
    

    在這種情況下,你會得到

    1. 小的性能提升,因爲編譯器不檢查溢出。鑰匙簡單
    2. 小碼
    +0

    沉默的投票不會爲社區提供任何好處。如果你認爲asnwer是錯誤的/不完整的,即使你已經低估了,至少要解釋你的立場,也要寫下來。 –