yes, It is a data race.
But the problem mentioned by op is not caused by data race.
On Tuesday, September 12, 2017 at 3:59:32 AM UTC-4, Konstantin Khomoutov
wrote:
>
> On Wed, Sep 06, 2017 at 04:26:09AM -0700, T L wrote:
>
> > > > It is just weird that the evaluation timing of *p is different to
> other
> > > expressions, such as, *p+0, *p*1, func()int{return *p}m etc.
> > >
> > > The value depends on a data race so it's entirely undefined in all
> cases.
> > > That the actual outcome then depends on trivial differences that may
> affect
> > > CPU loads/stores, instruction ordering, register usage, etc isn't
> > > surprising.
> >
> > I don't think it is so complex. It is simply that gc adopts a different
> > route for evaluate pointer dereference.
>
> It's not complex, it's a simple data race.
>
> In your code
>
> var num = 10
> var p = &num
>
> c := make(chan int)
>
> go func() {
> c <- func()int{return *p}()
> }()
>
> time.Sleep(time.Second)
> num++
> fmt.Println(<-c)
>
> two goroutines -- the main one and the one you spawned are accessing the
> variable "num" concurrently without any synchronization.
>
> Some assorted points to may be make this more clear:
>
> * Sleeping for "just enough" time is not a form of synchronization.
>
> * You might be driven away by using a function literal which is
> immediately executed but that's pretty much equivalent to just doing
>
> c <- *p
>
> which supposedly makes the data race over the variable "num"
> even more obvious.
>
> * You might keep false assumption that function literals producing
> function values close over values -- that is, they work sort of as
> code templates. This is wrong: they close over variables, so in your
> example the function value you're constructing before running it on
> a separate goroutine closes over the variable "p", not the value
> obtained by dereferencing it at the time of producing that function
> value.
>
>
> To explain what happens, step by step, the statement
>
> go func() {
> c <- func()int{return *p}()
> }()
>
> in your example:
>
> 1) Creates a function value which is a closure consisting of the
> anonymous function
>
> func() {
> c <- func()int{return *p}()
> }
>
> and a reference to the variable "p" in the scope of the function
> main().
>
> 2) Spawns a goroutine and tells it to execute the function value
> created on the previous step.
>
> 3) When run, the function executes the function value produced by
> the expression on the right side of the channel send statement.
>
> That function value is itself a closure, closing over the variable
> "p" in the scope of its lexical parent function -- the closure
> created on step 1.
>
> The pointer gets dereferenced and this action accesses the memory
> location "backing" the variable "num".
> The same memory is accessed concurrently from the main goroutine.
>
> Since there is no synchronization done for _this_ access, you have
> a data race. The fact you have a channel send/receive has nothing
> to do with regard to accessing the memory of the "num" variable
> since both goroutines do it before attempting its respective channel
> send/receive operations. During that time, they may have being run on
> different hardware CPUs or one of the goroutines might have no chance to
> run at all. Running on different CPUs involves a whole lot of
> interesting problems, of which the most glaring are reordering of memory
> accesses and coherence problems of CPU caches.
>
> Please read [1, 2] and [3] (which is written by one of the Go core devs).
>
> 1. http://preshing.com/20120515/memory-reordering-caught-in-the-act/
> 2.
> http://preshing.com/20120710/memory-barriers-are-like-source-control-operations/
>
> 3.
> https://software.intel.com/en-us/blogs/2013/01/06/benign-data-races-what-could-possibly-go-wrong
>
>
>
--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.