2011-01-06 14 views
8

Ho la seguente classeRandom.Next() restituisce talvolta stesso numero in thread separati

class Program 
{ 
    static Random _Random = new Random(); 

    static void Main(string[] args) 
    { 
     ... 
     for (int i = 0; i < no_threads; ++i) 
     { 
     var thread = new Thread(new ThreadStart(Send)); 
     thread.Start(); 
     } 
     ... 
    } 

    static void Send() 
    { 
     ... 
     int device_id = _Random.Next(999999); 
     ... 
    } 
} 

Il codice crea il numero specificato di fili, inizia ciascuno, e assegna ogni thread un casuale device_id. Per qualche motivo, i primi due thread creati spesso hanno lo stesso device_id. Non riesco a capire perché questo succede.

+0

Questo è statisticamente corretto, come se si lancia 2 dadi che a volte ti danno lo stesso numero, più casuale non è thread-safe - > http://blogs.msdn.com/b/pfxteam/archive/2009/02/19/9434171.aspx – dvhh

+3

@Mitch: nessuna delle domande collegate ha a che fare con la stessa situazione. È solo la sicurezza del thread che è rilevante qui, poiché c'è solo un'istanza di Random. –

+0

@Jon: sì, è vero. –

risposta

23

Random non è thread-safe - non si dovrebbe utilizzare la stessa istanza da più thread. Può diventare molto peggio di un semplice ritorno degli stessi dati, utilizzando da più thread, è possibile ottenerlo "bloccato" in uno stato in cui sarà sempre return 0, IIRC.

Ovviamente non si vuole solo creare una nuova istanza per ogni thread più o meno allo stesso tempo, come finiranno con gli stessi semi ...

Ho un article che va in dettagli di questo e fornisce un'implementazione che istanzia pigramente un'istanza di Random per thread usando un seme incrementale.

+0

Avevo il sospetto ma non ero sicuro nemmeno dopo aver controllato MSDN. Controllerò anche il tuo articolo. Grazie. – dandan78

+0

Vedere anche [MiscUtil.StaticRandom] di Jon Skeet (http://www.yoda.arachsys.com/csharp/miscutil/). – Brian

4

Casuale è un generatore di numeri pseudo-casuali e non c'è nulla che impedisca di restituire lo stesso risultato per più chiamate. Dopo tutto, c'è una probabilità che questo accada. Per non parlare di ciò secondo lo documentation:

Qualsiasi istanza membri non è garantito per essere thread-safe.

Quindi non si dovrebbe chiamare il metodo Next da più thread.

1

Il codice di esempio mostra solo un utilizzo di _Random per thread. Supponendo che questo sia il caso, potresti anche generare il numero casuale nel ciclo principale for e passare il numero casuale in ciascun thread come parametro.

for (int i = 0; i < no_threads; ++i) 
{ 
     var thread = new Thread(new ThreadStart(Send)); 
     thread.Start(_Random.Next(999999)); 
} 

e quindi modificare la funzione filo di accettare il parametro:

static void Send(int device_id) 
{ 
    ... 
    //int device_id = _Random.Next(999999); 
    ... 
} 
Problemi correlati