2010-04-26 3 views
5

Ich benutze .NET, um ein künstliches Lebenprogramm zu schaffen, und ich benutze Pseudozufallsklasse C#, die in einem Singleton definiert wird. Die Idee ist, dass, wenn ich den gleichen Zufallszahlengenerator in der gesamten Anwendung verwende, ich den Seed nur speichern und dann von dem Seed neu laden könnte, um einen bestimmten interessanten Lauf neu zu berechnen.C# Zufallszahlengenerator, der in einem Zyklus stecken bleibt

Ich wollte auch eine Methode, die mir zwei verschiedene Zufallszahlen geben könnte.

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);    
    } 

Das Problem ist, dass manchmal rnd.Next(minValue,maxValue immer minValue zurückgibt. Wenn ich an dieser Stelle einen Haltepunkt einstelle und versuche, ein Double zu erstellen und auf rnd.NextDouble() zu setzen, wird 0.0 zurückgegeben. Wer weiß, warum das passiert?

Ich weiß, dass es ein Pseudozufallszahlengenerator ist, aber ehrlich gesagt, ich hatte nicht erwartet, dass es bei 0 sperren. Der Zufallszahlengenerator wird von mehreren Threads zugegriffen ... könnte dies die Ursache des Problems sein ?

EDIT: Danke, das Problem endete Threadsicherheit.

Dies ist die neue Version der Klasse.

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; 
     } 
    } 
} 

Antwort

3

Wenn Sie nur einen RNG für mehrere Threads verwenden, auch wenn Sie den Startwert speichern, können Sie beim nächsten Start der Anwendung nicht die gleichen Nummern generieren, da Sie nicht sicher sind, ob die Aufrufe an den RNG von den verschiedenen Threads wird in der gleichen Reihenfolge sein.

Wenn Sie eine feste/bekannte Anzahl von Threads haben, erstellen Sie einen RNG pro Thread und speichern Sie jeden Seed.

Vergessen Sie, was ich gerade gesagt habe, wenn Sie 100% sicher sind, dass jeder Thread den RNG mit der exakt gleichen Reihenfolge wie beim letzten Mal aufruft, wenn Sie den gleichen Seed verwenden.

+0

Whoops, ich hatte diesen Postantwortfenster ein bisschen zu lange offen gelassen, +1 ... genau das wollte ich sagen! –

+0

Danke, du warst genau richtig. Ich habe deinen Kommentar als Antwort akzeptiert, um dir noch mehr Karma zu geben: P Auch, danke, dass du mir von dem anderen Problem mit mehreren Threads erzählt hast, es kam mir nicht in den Sinn! –

11

Die Klasse Random ist nicht threadsicher.

Sie sollten Ihre static Instanz [ThreadStatic], oder schützen Sie sie mit einem Schloss.

+0

+1 für ['[ThreadStatic]'] (http://msdn.microsoft.com/en-us/library/system.threadstaticattribute.aspx) - wusste nie darüber. –

1

Die Idee ist, dass, wenn ich den gleichen Zufallszahlengenerator in der gesamten Anwendung verwende, ich nur den Seed speichern und dann aus dem Seed neu laden könnte, um einen bestimmten interessanten Lauf neu zu berechnen.

Sie benötigen dafür tatsächlich keine Singleton-Instanz des Zufallsgenerators. Wenn Sie zwei separate Instanzen von Random mit derselben seed initialisieren, werden sie genau die gleiche Sequenz erzeugen.

Mein Rat ist, speichern Sie den Samen, aber loswerden der Singleton.

1

Ich muss nicht einmal die Random-Klasse nachschlagen, die "alle Instanzmethoden dieser Klasse oder nicht threadsicher" kennt. Das gilt für alle .NET-Klassen mit sehr wenigen Ausnahmen.

Also ja, es ist das Multithreading. Aber Sie haben nicht erwähnt, dass auch MaxValue> MinValue überprüft wird.

+0

Eigentlich überprüfe ich das, aber du hast Recht ... das Problem ist Thread-Sicherheit. –