diff --git a/rand/example_test.go b/rand/example_test.go index 47f21fdfd..8faad517f 100644 --- a/rand/example_test.go +++ b/rand/example_test.go @@ -132,3 +132,32 @@ func ExampleShuffle_slicesInUnison() { // B: 2 // C: 3 } + +func ExampleLockedSource() { + r := rand.New(new(rand.LockedSource)) + r.Seed(42) // Try changing this number! + answers := []string{ + "It is certain", + "It is decidedly so", + "Without a doubt", + "Yes definitely", + "You may rely on it", + "As I see it yes", + "Most likely", + "Outlook good", + "Yes", + "Signs point to yes", + "Reply hazy try again", + "Ask again later", + "Better not tell you now", + "Cannot predict now", + "Concentrate and ask again", + "Don't count on it", + "My reply is no", + "My sources say no", + "Outlook not so good", + "Very doubtful", + } + fmt.Println("Magic 8-Ball says:", answers[r.Intn(len(answers))]) + // Output: Magic 8-Ball says: Most likely +} diff --git a/rand/rand.go b/rand/rand.go index a369bc775..173c0f520 100644 --- a/rand/rand.go +++ b/rand/rand.go @@ -212,7 +212,8 @@ func (r *Rand) Shuffle(n int, swap func(i, j int)) { // Read generates len(p) random bytes and writes them into p. It // always returns len(p) and a nil error. -// Read should not be called concurrently with any other Rand method. +// Read should not be called concurrently with any other Rand method unless +// the underlying source is a LockedSource. func (r *Rand) Read(p []byte) (n int, err error) { if lk, ok := r.src.(*LockedSource); ok { return lk.Read(p, &r.readVal, &r.readPos) @@ -246,10 +247,10 @@ func read(p []byte, src Source, readVal *uint64, readPos *int8) (n int, err erro * Top-level convenience functions */ -var globalRand = New(&LockedSource{src: NewSource(1).(*PCGSource)}) +var globalRand = New(&LockedSource{src: *NewSource(1).(*PCGSource)}) -// Type assert that globalRand's source is a LockedSource whose src is a *rngSource. -var _ *PCGSource = globalRand.src.(*LockedSource).src +// Type assert that globalRand's source is a LockedSource whose src is a PCGSource. +var _ PCGSource = globalRand.src.(*LockedSource).src // Seed uses the provided seed value to initialize the default Source to a // deterministic state. If Seed is not called, the generator behaves as @@ -335,10 +336,12 @@ func NormFloat64() float64 { return globalRand.NormFloat64() } func ExpFloat64() float64 { return globalRand.ExpFloat64() } // LockedSource is an implementation of Source that is concurrency-safe. -// It is just a standard Source with its operations protected by a sync.Mutex. +// A Rand using a LockedSource is safe for concurrent use. +// +// The zero value of LockedSource is valid, but should be seeded before use. type LockedSource struct { lk sync.Mutex - src *PCGSource + src PCGSource } func (s *LockedSource) Uint64() (n uint64) { @@ -365,7 +368,7 @@ func (s *LockedSource) seedPos(seed uint64, readPos *int8) { // Read implements Read for a LockedSource. func (s *LockedSource) Read(p []byte, readVal *uint64, readPos *int8) (n int, err error) { s.lk.Lock() - n, err = read(p, s.src, readVal, readPos) + n, err = read(p, &s.src, readVal, readPos) s.lk.Unlock() return }