-3

I was disturbed by a question,

should we add lock if only one thread write variable, and other thread just read variable?

so I write such code to test it

package main

import (
    "fmt"
    "runtime"
    "sync"
    "time"
)

var lock sync.RWMutex
var i = 0

func main() {
    runtime.GOMAXPROCS(2)
    go func() {
        for {
            fmt.Println("i am here", i)
            time.Sleep(time.Second)
        }
    }()
    for {
        i += 1
    }
}

The result is keep print i am here 0 even after second of time. I know a little about Memory barrier or cpu cache. but how could it be cache for such a long time? I think after a few time, it should read variable I already changed.

Can anyone who is master go or computer system could help answer, please?


Update: i know it is a wrong way to update variable like this, i want to know why it is undefined in cpu/memory view.

peterSO
  • 158,998
  • 31
  • 281
  • 276
pete lin
  • 358
  • 1
  • 4
  • 13
  • 4
    Accessing unsynchronized memory is **undefined** behavior. You should expect nothing. Use proper synchronization. See possible duplicate: [Is it safe to read a function pointer concurrently without a lock?](https://stackoverflow.com/questions/41406501/is-it-safe-to-read-a-function-pointer-concurrently-without-a-lock/41407827#41407827) – icza Jun 20 '18 at 08:30
  • interesting thing is it changes if you put another sleep in second for loop. my guess is it's cached in cpu and changes whenever its free to read (saying so cuz both i has the same address in memory) – CallMeLoki Jun 20 '18 at 08:55
  • @danicheeta yes, i found it too, even a ns sleep will work. what do you mean free to read? – pete lin Jun 20 '18 at 09:30
  • I suggest reading about the [Go Memory Model](https://golang.org/ref/mem) – dev.bmax Jun 20 '18 at 09:35
  • @petelin: Synchronization can be very expensive. Therefore, when it may be expensive, you must explicitly request it. – peterSO Jun 20 '18 at 14:08

3 Answers3

4

You have a data race. Therefore, the results are undefined.

package main

import (
    "fmt"
    "runtime"
    "sync"
    "time"
)

var lock sync.RWMutex
var i = 0

func main() {
    runtime.GOMAXPROCS(2)
    go func() {
        for {
            fmt.Println("i am here", i)
            time.Sleep(time.Second)
        }
    }()
    for {
        i += 1
    }
}

Output:

$ go run -race racer.go
==================
WARNING: DATA RACE
Read at 0x0000005e3600 by goroutine 6:
  main.main.func1()
      /home/peter/gopath/src/racer.go:17 +0x63

Previous write at 0x0000005e3600 by main goroutine:
  main.main()
      /home/peter/gopath/src/racer.go:22 +0x7b

Goroutine 6 (running) created at:
  main.main()
      /home/peter/gopath/src/racer.go:15 +0x4f
==================
i am here 3622
i am here 43165250
i am here 86147697
^Csignal: interrupt
$

References:

Data Race Detector

Benign Data Races: What Could Possibly Go Wrong?

peterSO
  • 158,998
  • 31
  • 281
  • 276
1

should we add lock if only one thread write variable, and other thread just read variable?

Yes. Always. No arguing here.

Your test code proves and disproves nothing as its behaviour is undefined.

Volker
  • 40,468
  • 7
  • 81
  • 87
  • thanks for you answer, it is undefined by go or cpu system? and could i know why it is undefined? i mean i write i in one thread, couldn't i assume read the modify from memory after a long time? – pete lin Jun 20 '18 at 10:00
  • 2
    "Undefined" means everything is undefined. Undefined behaviour offers **absolutely ** **no** guarantees whatsoever. Anything is (formally) possible. Your code **must** **not** have **any** undefined behaviour at all. – Volker Jun 20 '18 at 12:43
-1

finally, i find this answers, i know with a data race you will get a undefined behave, but i want to know why it behave like that currently.

this snap code is because complier just remove Add function, it never add.

so we have lesson, if you write a undefined behave, you may got a moon - -

complier will treat you code as rubbish, it does not have any value.

pete lin
  • 358
  • 1
  • 4
  • 13