diff --git a/doc/articles/race_detector.html b/doc/articles/race_detector.html index af348dfeb6..400d96b198 100644 --- a/doc/articles/race_detector.html +++ b/doc/articles/race_detector.html @@ -6,7 +6,7 @@

Introduction

-Data races are one of the most common and hardest to debug types of bugs in concurrent systems. A data race occurs when two goroutines access the same variable concurrently and at least one of the accesses is a write. See the The Go Memory Model for details. +Data races are one of the most common and hardest to debug types of bugs in concurrent systems. A data race occurs when two goroutines access the same variable concurrently and at least one of the accesses is a write. See the The Go Memory Model for details.

@@ -18,10 +18,10 @@ func main() { c := make(chan bool) m := make(map[string]string) go func() { - m["1"] = "a" // First conflicting access. + m["1"] = "a" // First conflicting access. c <- true }() - m["2"] = "b" // Second conflicting access. + m["2"] = "b" // Second conflicting access. <-c for k, v := range m { fmt.Println(k, v) @@ -96,18 +96,32 @@ GORACE="option1=val1 option2=val2"

The options are:

-
  • log_path (default stderr): The race detector writes + +

    Example: @@ -131,17 +145,17 @@ You can use it to exclude some code/tests under the race detector. For example: package foo // The test contains a data race. See issue 123. -func TestFoo(t *testing.T) { +func TestFoo(t *testing.T) { // ... } // The test fails under the race detector due to timeouts. -func TestBar(t *testing.T) { +func TestBar(t *testing.T) { // ... } // The test takes too long under the race detector. -func TestBaz(t *testing.T) { +func TestBaz(t *testing.T) { // ... } @@ -170,7 +184,7 @@ func main() { wg.Add(5) for i := 0; i < 5; i++ { go func() { - fmt.Println(i) // Not the 'i' you are looking for. + fmt.Println(i) // Not the 'i' you are looking for. wg.Done() }() } @@ -191,7 +205,7 @@ func main() { wg.Add(5) for i := 0; i < 5; i++ { go func(j int) { - fmt.Println(j) // Good. Read local copy of the loop counter. + fmt.Println(j) // Good. Read local copy of the loop counter. wg.Done() }(i) } @@ -217,7 +231,7 @@ func ParallelWrite(data []byte) chan error { f1.Close() }() } - f2, err := os.Create("file2") // The second conflicting write to err. + f2, err := os.Create("file2") // The second conflicting write to err. if err != nil { res <- err } else { @@ -236,9 +250,11 @@ The fix is to introduce new variables in the goroutines (note :=):

    +			...
     			_, err := f1.Write(data)
     			...
     			_, err := f2.Write(data)
    +			...
     

    Unprotected global variable

    @@ -286,14 +302,14 @@ func LookupService(name string) net.Addr {

    Primitive unprotected variable

    -Data races can happen on variables of primitive types as well (bool, int, int64), like in the following example: +Data races can happen on variables of primitive types as well (bool, int, int64, etc.), like in the following example:

    -type Watchdog struct { last int64 }
    +type Watchdog struct{ last int64 }
     
     func (w *Watchdog) KeepAlive() {
    -	w.last = time.Now().UnixNano()  // First conflicting access.
    +	w.last = time.Now().UnixNano() // First conflicting access.
     }
     
     func (w *Watchdog) Start() {
    @@ -316,11 +332,11 @@ Even such “innocent” data races can lead to hard to debug problems c
     
     

    A typical fix for this race is to use a channel or a mutex. -To preserve the lock-free behavior, one can also use the sync/atomic package. +To preserve the lock-free behavior, one can also use the sync/atomic package.

    -type Watchdog struct { last int64 }
    +type Watchdog struct{ last int64 }
     
     func (w *Watchdog) KeepAlive() {
     	atomic.StoreInt64(&w.last, time.Now().UnixNano())