Memory barriers

725 views
Skip to first unread message

drago....@gmail.com

unread,
Feb 3, 2014, 5:51:16 PM2/3/14
to golan...@googlegroups.com
Hello,
If I have the following code snippet, and the env. GOMAXPROC>1

func main() {
    a:=6
    go func() {
       b:=a 
    }()
}

and presumably the second goroutine is executed on other processor than the main func, will variable b will always get the value written to a, in the main func (and no some previous CPU cached value of a). There are no explicit memory barriers after a assignment.
Thank you.

minux

unread,
Feb 3, 2014, 5:56:17 PM2/3/14
to drago....@gmail.com, golang-nuts

No. Please read golang.org/ref/mem regarding Go memory model.

drago....@gmail.com

unread,
Feb 3, 2014, 5:58:47 PM2/3/14
to golan...@googlegroups.com, drago....@gmail.com
I have missed that. Thank you very much @minux.

Felix

unread,
Feb 3, 2014, 6:38:07 PM2/3/14
to golan...@googlegroups.com, drago....@gmail.com
a happens before b; and 
b happens after a; so sometime 
in the future b will equal a

Maxim Khitrov

unread,
Feb 3, 2014, 6:57:45 PM2/3/14
to minux, Dragomir Ivanov, golang-nuts
Why not? The value of a has to be copied in the main goroutine to
create the closure, then the value of the copy is assigned to b in the
new goroutine. Both are "happens-before" relationships within a single
goroutine. Now if you passed a pointer to a and tried to dereference
it in the new goroutine, then you might not get 6 back.

minux

unread,
Feb 3, 2014, 7:02:45 PM2/3/14
to Maxim Khitrov, golang-nuts, drago....@gmail.com


On Feb 3, 2014 6:58 PM, "Maxim Khitrov" <m...@mxcrypt.com> wrote:
>
> On Mon, Feb 3, 2014 at 5:56 PM, minux <minu...@gmail.com> wrote:
> >
> > On Feb 3, 2014 5:51 PM, <drago....@gmail.com> wrote:
> >>
> >> Hello,
> >> If I have the following code snippet, and the env. GOMAXPROC>1
> >>
> >> func main() {
> >>     a:=6
> >>     go func() {
> >>        b:=a
> >>     }()
> >> }
> >>
> >> and presumably the second goroutine is executed on other processor than
> >> the main func, will variable b will always get the value written to a, in
> >> the main func (and no some previous CPU cached value of a). There are no
> >> explicit memory barriers after a assignment.
> > No. Please read golang.org/ref/mem regarding Go memory model.
> Why not? The value of a has to be copied in the main goroutine to
> create the closure, then the value of the copy is assigned to b in the

the new goroutine closes over &a, not a.

Caleb Spare

unread,
Feb 3, 2014, 7:04:18 PM2/3/14
to minux, Maxim Khitrov, golang-nuts, drago....@gmail.com
The assignment happens-before the creation of the goroutine at all.


--
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 golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Maxim Khitrov

unread,
Feb 3, 2014, 7:06:10 PM2/3/14
to minux, golang-nuts, Dragomir Ivanov
On Mon, Feb 3, 2014 at 7:02 PM, minux <minu...@gmail.com> wrote:
>
> On Feb 3, 2014 6:58 PM, "Maxim Khitrov" <m...@mxcrypt.com> wrote:
>>
>> On Mon, Feb 3, 2014 at 5:56 PM, minux <minu...@gmail.com> wrote:
>> >
>> > On Feb 3, 2014 5:51 PM, <drago....@gmail.com> wrote:
>> >>
>> >> Hello,
>> >> If I have the following code snippet, and the env. GOMAXPROC>1
>> >>
>> >> func main() {
>> >> a:=6
>> >> go func() {
>> >> b:=a
>> >> }()
>> >> }
>> >>
>> >> and presumably the second goroutine is executed on other processor than
>> >> the main func, will variable b will always get the value written to a,
>> >> in
>> >> the main func (and no some previous CPU cached value of a). There are
>> >> no
>> >> explicit memory barriers after a assignment.
>> > No. Please read golang.org/ref/mem regarding Go memory model.
>> Why not? The value of a has to be copied in the main goroutine to
>> create the closure, then the value of the copy is assigned to b in the
> the new goroutine closes over &a, not a.

Sorry, you're right. I've been doing nothing but C coding for last
month and forgot how closures work :)

Benjamin Measures

unread,
Feb 3, 2014, 8:08:05 PM2/3/14
to golan...@googlegroups.com, drago....@gmail.com
On Monday, 3 February 2014 22:56:17 UTC, minux wrote:

No. Please read golang.org/ref/mem regarding Go memory model.

Doesn't the "go statement that starts a new goroutine happens before the goroutine's execution begins"?

Thus,
a:=6 // happens before
go func() { // happens before
    b:=a

Or am I missing something?

Jesse McNelis

unread,
Feb 3, 2014, 11:21:44 PM2/3/14
to Benjamin Measures, golang-nuts, Dragomir Ivanov
You're not missing anything.
a:=6 happens before the goroutine starts, so 'a' in the closure in the goroutine will be 6.
Thus b will be 6. Since 'a' is never modified again it's value remains the same.

If 'a' was changed in either of the goroutines past the 'go' statement additional synchronisation would be required.

 


--
=====================
http://jessta.id.au

Artem Miolini

unread,
Feb 4, 2014, 1:11:28 AM2/4/14
to drago....@gmail.com, golan...@googlegroups.com
Hi!

Try next code:

func main() {
    a:=6
    go func(value int) {
        b:=value
    } (a)
}


--

Dmitry Vyukov

unread,
Feb 4, 2014, 1:28:33 AM2/4/14
to mio...@gmail.com, Dragomir Ivanov, golang-nuts
On Tue, Feb 4, 2014 at 10:11 AM, Artem Miolini <mio...@gmail.com> wrote:
> Hi!
>
> Try next code:

Why does he need to try this code?

Pierre Durand

unread,
Feb 4, 2014, 4:00:33 AM2/4/14
to golan...@googlegroups.com, mio...@gmail.com, Dragomir Ivanov

Jesse McNelis

unread,
Feb 4, 2014, 4:24:06 AM2/4/14
to Pierre Durand, golang-nuts, Artem Miolini, Dragomir Ivanov
On Tue, Feb 4, 2014 at 8:00 PM, Pierre Durand <pierre...@gmail.com> wrote:

The fun thing about data races is that some times they happen and sometimes they don't.
In that program the value of 'a' is undefined according to the memory model. It could be 6 or 7 or some completely different value when the spawned goroutine prints it.

Pierre Durand

unread,
Feb 4, 2014, 4:28:20 AM2/4/14
to golan...@googlegroups.com, Pierre Durand, Artem Miolini, Dragomir Ivanov, jes...@jessta.id.au
If you don't change the value of "a", is it safe to do that?

Dragomir Ivanov

unread,
Feb 4, 2014, 4:29:59 AM2/4/14
to Jesse McNelis, Pierre Durand, golang-nuts, Artem Miolini
Jesse, 
Are you sure about that? In the Go memory model documentation it is said that:
a:=6 will happen before go statement, so it acts like barrier. So the printed value will be 6 or 7, but not anything else.

Nico

unread,
Feb 4, 2014, 5:02:57 AM2/4/14
to golan...@googlegroups.com
On 03/02/14 22:51, drago....@gmail.com wrote:
> func main() {
> a:=6
> go func() {
> b:=a
> }()
> }

The behaviour of this program is undefined.

It is possible (and so it happens in my machine) that main() finishes
before the goroutine has had a chance to run.

But if synchronisation between main and the goroutine is added, then the
answer to the original question is trivial.


package main

func main() {
a := 6
ch := make(chan struct{})
go func() {
b := a
println(b)
close(ch)
}()
<-ch
}

drago....@gmail.com

unread,
Feb 4, 2014, 5:10:30 AM2/4/14
to golan...@googlegroups.com
Thanks Nico, but the question was about memory synchronization. This particular example will exit before goroutine has chance to execute. Others have added sleep before main return, though. 

Nico

unread,
Feb 4, 2014, 5:18:50 AM2/4/14
to golan...@googlegroups.com
To make my point clear. I think the question is unanswerable unless a
synchronisation point is added within the goroutine. Once, this
synchronisation point is added the answer to your question in minux's
link to the memory model.

Sometime ago, I wrote a document that helps visualise these memory
barriers in go:


https://docs.google.com/document/d/1h5YSWCELBqH3ILW3HmkVIpCt2Gpn02FBSF50kPz921s/edit?pli=1

David Symonds

unread,
Feb 4, 2014, 5:38:31 AM2/4/14
to Nico, golang-nuts
On 4 February 2014 21:18, Nico <nicolas...@gmail.com> wrote:

> To make my point clear. I think the question is unanswerable unless a
> synchronisation point is added within the goroutine. Once, this
> synchronisation point is added the answer to your question in minux's link
> to the memory model.

There is a synchronisation point when the goroutine starts
(http://golang.org/ref/mem#tmp_4). The only undefined part of the
program's behaviour is that main may return and terminate the program
without waiting for the anonymous function to complete, but the "b :=
a" inside that function is perfectly well-defined.

Nico

unread,
Feb 4, 2014, 5:46:34 AM2/4/14
to golang-nuts
The synchronisation at the goroutine start is not enough. If no
synchronisation point is provided after the statement b := a, then the
memory model doesn't guarantee that that statement would be run before
the completion of main().

drago....@gmail.com

unread,
Feb 4, 2014, 5:54:10 AM2/4/14
to golan...@googlegroups.com
package main

import "time"

func main() {
a := 6
go func() {
b := a
println(b)
}()
time.Sleep(time.Second)
}

What needs to be done in this example, to be memory model correct? I don't understand. a:=6 "happens-before" starting of the goroutine(by the memory model docs). b:=a "happens-before" printing of b.

Nico

unread,
Feb 4, 2014, 6:01:32 AM2/4/14
to golan...@googlegroups.com
On 04/02/14 10:54, drago....@gmail.com wrote:
> package main
>
> import "time"
>
> func main() {
> a := 6
> go func() {
> b := a
> println(b)
> }()
> time.Sleep(time.Second)
> }
>
> What needs to be done in this example, to be memory model correct? I
> don't understand. a:=6 "happens-before" starting of the goroutine(by the
> memory model docs). b:=a "happens-before" printing of b.

The memory model does not guarantee that b:=a happens-before the end of
main(), it only ensures that the goroutine is started before time.Sleep.

Henrik Johansson

unread,
Feb 4, 2014, 6:19:17 AM2/4/14
to Nico, golang-nuts, David Symonds
Correct me if I am wrong but as David said the closure is guaranteed to be created before the the goroutine starts right?
That would make it consistent.




--
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 golang-nuts+unsubscribe@googlegroups.com.

Nico

unread,
Feb 4, 2014, 6:32:10 AM2/4/14
to golang-nuts
On 04/02/14 11:19, Henrik Johansson wrote:
> Correct me if I am wrong but as David said the closure is guaranteed to
> be created before the the goroutine starts right?
> That would make it consistent.

what do you mean by "created before the goroutine starts"?

I don't know the details but I imagine that a closure is created during
compilation. If the closure was taking any arguments, the arguments
would be evaluated at the point where the go statement is.

I think the reason why channels were created in Go was to avoid all
these subtleties. It is possible to share memory by defining
synchronisation points between goroutines, but it's much easier to share
memory by communicating through channels.

chris dollin

unread,
Feb 4, 2014, 6:38:20 AM2/4/14
to Nico, golang-nuts
On 4 February 2014 11:32, Nico <nicolas...@gmail.com> wrote:

I don't know the details but I imagine that a closure is created during compilation.

Closures are created at runtime [1].

Chris

[1] In general. Sometimes they can be optimised away. But then, sometimes
    a := 1 + 2 can be optimised away.

--
Chris "allusive" Dollin

Nico

unread,
Feb 4, 2014, 6:47:39 AM2/4/14
to golang-nuts
Perhaps I'm misunderstanding what a closure is. I thought a closure in
Go was something like:

f, ... := func (...) (...) {
...
}

and I thought that that piece of code was compiled with the rest of
program. Does Go have any JIT capabilities? The closer thing to that I
can think of is MakeFunc in the package reflect, but it still takes a
function as an argument.

David Symonds

unread,
Feb 4, 2014, 6:48:46 AM2/4/14
to Nico, golang-nuts
You and I are in violent agreement. I was pointing out that the "b :=
a" statement in the original program has well-defined behaviour. You
are saying that there's no guarantee that that statement will run; I
agree. All I'm saying is that that statement -- if it does run -- is
well-defined.

Henrik Johansson

unread,
Feb 4, 2014, 6:50:01 AM2/4/14
to Nico, golang-nuts
It closes over the address of the variables I believe (knock, knock) which is why you can see the classic for loop behavior of seeing only the value of the last iteration of the loop.



Nico

unread,
Feb 4, 2014, 6:54:57 AM2/4/14
to golang-nuts
"in violent agreement" I like that expression, I may borrow it in the
future.

David Symonds

unread,
Feb 4, 2014, 6:55:23 AM2/4/14
to Nico, golang-nuts
On 4 February 2014 22:47, Nico <nicolas...@gmail.com> wrote:

> Perhaps I'm misunderstanding what a closure is. I thought a closure in Go
> was something like:
>
> f, ... := func (...) (...) {
> ...
> }
>
> and I thought that that piece of code was compiled with the rest of program.

Every function literal is a closure. A Go program runs in a common
memory space. The "a" var in the original program is allocated
somewhere (whether on the stack or heap), and both the main goroutine
and the new one can access its memory using that name.

The program code is compiled with the program the same as usual; the
only thing that makes a "closure" special is that it "closes" over
variables (namely, references variables that are otherwise local to
another goroutine) and shares that memory.

chris dollin

unread,
Feb 4, 2014, 7:04:37 AM2/4/14
to Nico, golang-nuts
On 4 February 2014 11:47, Nico <nicolas...@gmail.com> wrote:
Perhaps I'm misunderstanding what a closure is. I thought a closure in Go was something like:

f, ... := func (...) (...) {
        ...
}

and I thought that that piece of code was compiled with the rest of program.

There's a function literal, func(args){body}, whose execution at run-time
creates a closure (which is a function with its environment captured and
closed into it).

I would not use the term "closure" to refer to the compile-time object but
maybe I'm just picky.
 
Does Go have any JIT capabilities?

I would not say so, but it depends what counts as a "JIT capability".

Chris

--
Chris "allusive" Dollin

Michael Jones

unread,
Feb 4, 2014, 7:08:30 AM2/4/14
to David Symonds, Nico, golang-nuts
One minor point about the sample program (not about memory consistency per se) but about closures in this kind of situation. If you change

func main() {
    a:=6
    go func() {
       b:=a 
    }()
}

to 

func main() {
    a:=6
    go func(value int) {
       b:=value
    }(a)
}

then you're not stressing the details of consistency guarantees but rather sidestepping them completely by binding the value at the time of goroutine invocation. Everyone in the thread likely understands this, but if you've forgotten, remember that closure semantic vagueness is overcome by both communication channels and by function arguments.


--
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 golang-nuts...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.



--
Michael T. Jones | Chief Technology Advocate  | m...@google.com |  +1 650-335-5765

drago....@gmail.com

unread,
Feb 5, 2014, 10:44:34 AM2/5/14
to golan...@googlegroups.com
Nico, thanks a lot for your document. It helped me to shed some light on Go's memory model.
I can't understand why http://play.golang.org/p/UeHAShi_dS example of you, exits immediately. Can you explain.
If I put one trace line, It runs for 10 secs as I expected it to run: http://play.golang.org/p/S6AJD0HNz0

Thanks.

James Bardin

unread,
Feb 5, 2014, 10:59:20 AM2/5/14
to golan...@googlegroups.com, drago....@gmail.com


On Wednesday, February 5, 2014 10:44:34 AM UTC-5, drago....@gmail.com wrote:
Nico, thanks a lot for your document. It helped me to shed some light on Go's memory model.
I can't understand why http://play.golang.org/p/UeHAShi_dS example of you, exits immediately. Can you explain.
If I put one trace line, It runs for 10 secs as I expected it to run: http://play.golang.org/p/S6AJD0HNz0


If you execute it locally it will run fine. It has to do with the playground's time being "magic", and since there's no visible changes happening, it runs pretty much instantly. Not sure if this case is a bug or not.

Dragomir Ivanov

unread,
Feb 5, 2014, 11:03:37 AM2/5/14
to James Bardin, golang-nuts
Since there is no visual ( fmt.XXXX call ), playground sleeps much smaller amount of time in time.Sleep(time.Second) ( probably doesn't sleep at all ). Is that right?
If so, It makes sense now. Thanks, James.

Dmitry Vyukov

unread,
Feb 5, 2014, 11:06:02 AM2/5/14
to Dragomir Ivanov, James Bardin, golang-nuts
On Wed, Feb 5, 2014 at 8:03 PM, Dragomir Ivanov <drago....@gmail.com> wrote:
> Since there is no visual ( fmt.XXXX call ), playground sleeps much smaller
> amount of time in time.Sleep(time.Second) ( probably doesn't sleep at all ).
> Is that right?

Yes, it does not sleep at all.

> If so, It makes sense now. Thanks, James.
>
>
> On Wed, Feb 5, 2014 at 5:59 PM, James Bardin <j.ba...@gmail.com> wrote:
>>
>>
>>
>> On Wednesday, February 5, 2014 10:44:34 AM UTC-5, drago....@gmail.com
>> wrote:
>>>
>>> Nico, thanks a lot for your document. It helped me to shed some light on
>>> Go's memory model.
>>> I can't understand why http://play.golang.org/p/UeHAShi_dS example of
>>> you, exits immediately. Can you explain.
>>> If I put one trace line, It runs for 10 secs as I expected it to run:
>>> http://play.golang.org/p/S6AJD0HNz0
>>>>
>>>>
>>
>> If you execute it locally it will run fine. It has to do with the
>> playground's time being "magic", and since there's no visible changes
>> happening, it runs pretty much instantly. Not sure if this case is a bug or
>> not.
>
>

Konstantin Khomoutov

unread,
Feb 5, 2014, 12:03:12 PM2/5/14
to James Bardin, golan...@googlegroups.com, drago....@gmail.com
On Wed, 5 Feb 2014 07:59:20 -0800 (PST)
James Bardin <j.ba...@gmail.com> wrote:

> > Nico, thanks a lot for your document. It helped me to shed some
> > light on Go's memory model.
> > I can't understand why http://play.golang.org/p/UeHAShi_dS example
> > of you, exits immediately. Can you explain.
> > If I put one trace line, It runs for 10 secs as I expected it to
> > run: http://play.golang.org/p/S6AJD0HNz0
> >>
> If you execute it locally it will run fine. It has to do with the
> playground's time being "magic", and since there's no visible changes
> happening, it runs pretty much instantly. Not sure if this case is a
> bug or not.

Drago, you might find [1] integesting--it explains how this "magic
time" is actually implemented, among other things. Quite an amusing
read, as the rest of the articles is.

1. http://blog.golang.org/playground
Reply all
Reply to author
Forward
0 new messages