2010-04-26 70 views
5

我正在使用.NET創建一個人造生命程序,並且我使用的是C#僞隨機類在Singleton中定義的。我的想法是,如果我在整個應用程序中使用相同的隨機數生成器,我只能保存種子,然後從種子中重新加載以重新計算某個有趣的運行。C#隨機數發生器陷入一個循環

public sealed class RandomNumberGenerator : Random 
{ 
    private static readonly RandomNumberGenerator instance = new RandomNumberGenerator(); 

    RandomNumberGenerator() 
    { 

    } 

    public static RandomNumberGenerator Instance 
    { 
     get 
     { 
      return instance; 
     } 
    } 
} 

我也想要一種方法,可以給我兩個不同的隨機數。

public static Tuple<int, int> TwoDifferentRandomNumbers(this Random rnd, int minValue, int maxValue) 
    { 
     if (minValue >= maxValue) 
      throw new ArgumentOutOfRangeException("maxValue", "maxValue must be greater than minValue"); 
     if (minValue + 1 == maxValue) 
      return Tuple.Create<int, int>(minValue, maxValue); 

     int rnd1 = rnd.Next(minValue, maxValue); 
     int rnd2 = rnd.Next(minValue, maxValue); 
     while (rnd1 == rnd2) 
     {     
      rnd2 = rnd.Next(minValue, maxValue); 
     } 
     return Tuple.Create<int, int>(rnd1, rnd2);    
    } 

的問題是,有時rnd.Next(minValue,maxValue總是返回minValue。如果我此時斷點並嘗試創建一個雙精度值並將其設置爲rnd.NextDouble(),則返回0.0。任何人都知道這是爲什麼發生?

我知道這是一個僞隨機數發生器,但坦率地說,我沒有想到它鎖定在0.隨機數發生器正在從多個線程訪問......這可能是問題的根源?

編輯:謝謝,問題最終成爲線程安全。

這是該課程的新版本。

public sealed class RandomNumberGenerator : Random 
{ 
    private static Random _global = new Random(); 
    [ThreadStatic] 
    private static Random _localInstance; 

    RandomNumberGenerator() 
    { 

    } 

    public static Random Instance 
    { 
     get 
     { 
      Random inst = _localInstance; 
      if (inst == null) 
      { 
       int seed; 
       lock (_global) seed = _global.Next(); 
       _localInstance = inst = new Random(seed); 
      } 
      return _localInstance; 
     } 
    } 
} 

回答

3

如果即使保存種子,也只對多個線程使用一個RNG,但下次啓動應用程序時將無法生成相同的數字,因爲您不能確定對來自不同線程的RNG將具有相同的順序。

如果您有一個固定/已知數量的線程,請爲每個線程創建一個RNG並保存每個種子。

忘記我剛剛說的話,如果您100%確定每個線程都會按照與上次使用相同種子的順序完全相同的順序調用RNG。

+0

哎呦,我已經離開這個帖子的答案窗口打開太久了,+1 ......這正是我想說的! – 2010-04-26 15:01:37

+0

謝謝,你完全正確。我接受你的評論作爲回答,給你更多的業力:P另外,謝謝你告訴我關於另一個多線程問題,它並沒有超出我的想象! – 2010-04-26 17:37:53

11

Random類不是線程安全的。

你應該讓你的static實例[ThreadStatic],或用鎖保護它。

+0

+1 [[[ThreadStatic]'](http://msdn.microsoft.com/en-us/library/system.threadstaticattribute.aspx) - 從來不知道這一點。 – 2013-07-14 23:50:27

1

想法是,如果我在整個應用程序中使用相同的隨機數生成器,我只能保存種子,然後從種子重新加載以重新計算某個有趣的運行。

實際上您並不需要RNG的單例實例。如果將Random的兩個獨立實例初始化爲相同的seed,則它們將產生完全相同的序列。

我的建議是,保存種子,但擺脫單身。

1

我甚至不需要查看Random類就知道「這個類的所有實例方法或者不是線程安全的」。這適用於所有的.NET類,除了極少數例外。

所以是的,這是多線程。但是您還沒有提到驗證MaxValue> MinValue。

+0

其實,我確實檢查過,但你是對的......問題是線程安全。 – 2010-04-26 17:34:44