# HG changeset patch # User Pauli Nieminen # Date 1404227086 -10800 # Tue Jul 01 18:04:46 2014 +0300 # Node ID 423bfcb6b3ce1f241cb972efb4c7d9354c60086f # Parent 5f9dfe6b0789dccf3a60bf8ffb4c4e015e97c211 Make rngSource implementation thread safe It is relatively simple to make default math/rand implementation thread safe allowing multiple go routiness to use same random number generator if there is no requirement for deterministic number sequance. diff -r 5f9dfe6b0789 -r 423bfcb6b3ce src/pkg/math/rand/rng.go --- a/src/pkg/math/rand/rng.go Tue Jul 01 17:42:32 2014 +0300 +++ b/src/pkg/math/rand/rng.go Tue Jul 01 18:04:46 2014 +0300 @@ -4,6 +4,8 @@ package rand +import "sync/atomic" + /* * Uniform distribution * @@ -183,8 +185,7 @@ ) type rngSource struct { - tap int // index into vec - feed int // index into vec + feed int32 // index into vec vec [_LEN]int64 // current feedback register } @@ -201,8 +202,7 @@ // Seed uses the provided seed value to initialize the generator to a deterministic state. func (rng *rngSource) Seed(seed int64) { - rng.tap = 0 - rng.feed = _LEN - _TAP + atomic.StoreInt32(&rng.feed, _LEN - _TAP) seed = seed % _M if seed < 0 { @@ -230,17 +230,25 @@ // Int63 returns a non-negative pseudo-random 63-bit integer as an int64. func (rng *rngSource) Int63() int64 { - rng.tap-- - if rng.tap < 0 { - rng.tap += _LEN + feed := atomic.AddInt32(&rng.feed, -1) + + if feed < 0 { + feed += _LEN + if feed < 0 { + panic("Too many parallel calls to rngSource.Int63") + } + } + if feed == 0 { + atomic.AddInt32(&rng.feed, _LEN) } - rng.feed-- - if rng.feed < 0 { - rng.feed += _LEN + tap := feed + _TAP + + if tap >= _LEN { + tap -= _LEN } - x := (rng.vec[rng.feed] + rng.vec[rng.tap]) & _MASK - rng.vec[rng.feed] = x + x := (rng.vec[feed] + rng.vec[tap]) & _MASK + rng.vec[feed] = x return x }