Ted Pudlik
Ted Pudlik

Reputation: 705

How to create a thread-safe rand.Source?

The documentation for the standard-library rand.NewSource function states that,

Unlike the default Source used by top-level functions, this source is not safe for concurrent use by multiple goroutines.

Is there a way to create a thread-safe rand.Source?

Context: I have a type with a method that may be called by multiple go-routines, and this method uses random numbers. I want to support dependency injection for testing, so I can't use the default Source.

Upvotes: 4

Views: 7030

Answers (2)

Thundercat
Thundercat

Reputation: 121059

It's typical to use a sync.Mutex to ensure that a value or values are not accessed concurrently. Here's how to use a sync.Mutex to protect a rand.Source:

 var s = rand.NewSource(seed)
 var mu sync.Mutex

// lock/unlock when accessing source from a goroutine
mu.Lock()
i := s.Int63()
mu.Unlock()
 

The rand.Rand does not support concurrent use. If the application is using the rand.Source to create a rand.Rand, then protect the rand.Rand instead:

 var r = rand.New(rand.NewSource(seed))
 var mu sync.Mutex

// lock/unlock when accessing the rand from a goroutine
mu.Lock()
i := r.Int()
mu.Unlock()

The mutex used to protect the rand.Rand will also protect the rand.Source.

Upvotes: 8

Ted Pudlik
Ted Pudlik

Reputation: 705

After some sleuthing, I learned that the way to go is to protect the Source with a mutex. The standard library even contains an implementation, lockedSource, but the relevant type is not exported.

Upvotes: 2

Related Questions