I used math/big.Rat to represent numbers for accuracy. Denom() returns the denominator of number and Cmp() to compare two numbers. Both of them seems to be a pure read only functions. But when I ran my code with data race enabled, my whole assumption went wrong. When these functions are called concurrently with the same Rat instance, system throws data race scenario. Are these functions not read-only?
my test case
package main
import (
"math/big"
"sync"
)
func main() {
x := big.NewRat(5, 1)
wg := new(sync.WaitGroup)
// just for testing
for i := 0; i < 10; i++ {
go func() {
wg.Add(1)
defer wg.Done()
if i%2 == 0 {
x.Cmp(x)
} else {
x.Denom()
}
}()
}
wg.Wait()
}
When I check the source, every time Denom() function is called, it resets value in the same object. Is this an issue in the source? or I shouldn't take use Rat Denom() and Cmp() concurrently.
Denom() source from Golang for ref.
// Denom returns the denominator of x; it is always > 0.
400 // The result is a reference to x's denominator; it
401 // may change if a new value is assigned to x, and vice versa.
402 func (x *Rat) Denom() *Int {
403 x.b.neg = false // the result is always >= 0
404 if len(x.b.abs) == 0 {
405 x.b.abs = x.b.abs.set(natOne) // materialize denominator
406 }
407 return &x.b
408 }
I am adding few more points based on the discussions below and I accept that I made a mistake in using the varibale 'i' for the intended purpose (But still it will work to show the Data race scenario).
My point here is the operation performed in the Denom() won't have modification in the value represented by Rat. This can be performed upon creation of Rat to represent a value or a new value is set in the Rat. My concern is the repeated computaion (not concurrent safe) of same value again and again unless the value represented by the Rat is changed. Then why can't this be done at the creation/modifcation part?