The Go Memory Model

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Http://golang.org/ref/mem

The Go Memory Model

Version of March 6, 2012

Introduction
Happens before
Synchronization
initialization
Goroutine Creation
Goroutine Destruction
Channel Communication
Locks
Once
Incorrect synchronization

Introduction

The Go memory model specifies the conditions under whichreads of a variable in one goroutine can be guaranteed Toobserve V Alues produced by writes to the same variable in a different goroutine.

Happens before

Within a single goroutine, reads and writes must behaveas if they executed in the order specified by the program. That's, compilers and processors may reorder the reads and writesexecuted within a single goroutine if the reorder Ingdoes the behavior within that goroutineas defined by the language specification. Because of this reordering, the execution order Observedby one goroutine could differ from the order Perceivedby another. For example, if one goroutineexecutes a = 1; b = 2; , another might observethe updated value of b before the updated value Of .

To specify the requirements of reads and writes, we definehappensbefore, a partial order on the EXECUTIONOF memo RY operations in a Go program. If EventE1 Happensbefore event E2, then we say this E2 happens afterE1. Also, if E1 does not happen before E2 and does not happenafter E2, then we say that E1 andE2 happen concurrently.

Within a single goroutine, the Happens-before order was theorder expressed by the program.

A read R of a variable v is allowed to observe a writeW to v if both of the foll Owing hold:

    1. R does not happen before W.
    2. There is no other write W ' to that v happens afterW but before R.

To guarantee the A read R of a variable v observes Aparticular writeW v to, ensure that W is the OnlywriteR was allowed to observe. That's, R isguaranteed to observe W if both of the following hold:

    1. W happens before R.
    2. Any and write to the GKFX variable v either happens before W or after R.

This pair of conditions was stronger than the first pair;it requires that there be no other writes happeningconcurrently W ITHW or R.

Within a single goroutine,there was no concurrency, so the the other definitions is equivalent:a readR observes the Val UE written by the most recent write W to v . When multiple goroutines access a shared variable v , they must use synchronization events to Establishhappens-before Co Nditions that ensure reads observe Thedesired writes.

The initialization of variable with the v zero valuefor v ' s type behaves as a write in the memory model.

Reads and writes of values larger than a single machine wordbehave as multiple machine-word-sized operations in ANUNSPECIF IED order.

Synchronization

Initialization

Program initialization runs with a single goroutine,but that Goroutine could create other Goroutines,which run concurrently.

If A Package p imports package q , the completion of q ' s init functions happens before the start p of any of ' s.

The start of the function main.main happens afterall init functions has finished.

Goroutine creation

The go statement that starts a new goroutinehappens before the Goroutine ' s execution begins.

For example, the This program:

var a stringfunc f () {print (a)}func hello () {a = "Hello, world" Go f ()}

Calling would print at some point in the future hello "hello, world" (perhaps after have hello returned).

Goroutine Destruction

The exit of a goroutine is not guaranteed to happen Beforeany event in the program. For example, the This program:

var a stringfunc hello () {go func () {a = "Hello"} () print (a)}

athe assignment to isn't followed Byany synchronization event, so it's not guaranteed to beobserved by any other go Routine. In fact, an aggressive compiler might delete the entire go statement.

If the effects of a goroutine must be observed by another goroutine,use a synchronization mechanism such as a lock or Chan Nelcommunication to establish a relative ordering.

Channel Communication

Channel communication is the main method of Synchronizationbetween Goroutines. Each of the particular channelis matched to a corresponding receive is from the channel,usually in a different goroutine.

A Send on a channel happens before the correspondingreceive from that channel completes.

This program:

var c = make (chan int, ten) var a stringfunc f () {a = "Hello, world" C <-0}func main () {go f () <-cprint (a)}

is guaranteed to print "hello, world" . The write to a happens before the send c in, which happens beforethe corresponding receive on c completes, which Happens Beforethe print .

The closing of a channel happens before a receive that returns a zero valuebecause the channel is closed.

In the previous example, replacing and yields a program with the c <- 0 close(c) same guaranteed behavior.

A receive from the Unbuffered channel happens beforethe Send on the that channel completes.

This program (as above, but with the send and receive statements swapped andusing an unbuffered channel):

var c = make (chan int) var a stringfunc f () {a = ' Hello, world ' <-c}
Func main () {go f () C <-0print (a)}

is also guaranteed to print "hello, world" . athe write to happens before the receive c in, which happens beforethe corresponding send on c completes, which Happensbefore the print .

If the channel were buffered (e.g.,) then the program would isn't being c = make(chan int, 1) guaranteed to print "hello, world" . (It might print the empty string,crash, or do something else.)

Locks

syncThe package implements the data types, and sync.Mutex sync.RWMutex .

For any sync.Mutex or sync.RWMutex variable l and n < m, call n of l.Unlock() happens before callm< /c12> of l.Lock() returns.

This program:

var l sync. Mutexvar a stringfunc f () {a = "Hello, World" l.unlock ()}func main () {l.lock () go f () L.lock () print (a)}

is guaranteed to print "hello, world" . The first call to (in) Happensbefore the second call to l.Unlock() f (in l.Lock() main ) Returns,which happens before print the .

l.RLock sync.RWMutex l for variable, there are an n such that the l.RLock happens (returns) after Call n to and the l.Unlock matching l.RUnlock happensbefore call n+1 to l.Lock .

Once

The package sync provides a safe mechanism forinitialization in the presence of multiple Goroutinesthrough the use of th e Once type. Multiple threads can execute for once.Do(f) a particular f , but only one would run f() , and the other calls Blockuntil has returned.

A single Call of f() from once.Do(f) happens (returns) before any call of once.Do(f) returns.

In the program:

var a stringvar once sync. Oncefunc Setup () {a = "Hello, World"}func doprint () {once. Do (Setup) print (a)}func twoprint () {go doprint () Go Doprint ()}

Calling twoprint causes to be "hello, world" printed twice. The first call to twoprint runs setup once.

Incorrect synchronization

Note that a read R is observe the value written by a writeW, happens concurrently with R. Even if this occurs, it does not imply that reads happening afterRwould observe writes that happened before w.

In the program:

var A, B intfunc f () {a = 1b = 2}func g () {print (b) print (a)}func main () {go f () g ()}

It can happen that g prints and then 2 0 .

This fact invalidates a few common idioms.

Double-checked locking is a attempt to avoid the overhead of synchronization. For example, the program twoprint might beincorrectly written as:

var a stringvar done Boolfunc setup () {a = ' Hello, world ' done = True}func Doprint () {if!done {once. Do (Setup)}print (a)}func twoprint () {go doprint () Go Doprint ()}

But there was no guarantee that, doprint in, observing the write to done implies observing the write to a . Thisversion can (incorrectly) print an empty stringinstead of "hello, world" .

Another incorrect idiom is busy waiting for a value, as in:

var a stringvar done Boolfunc setup () {a = ' Hello, world ' done = True}func main () {go setup () for!done {}print (a)}

As before, there is no guarantee, in main , observing the write done to implies observing a the write to, so this P Rogram couldprint an empty string too. Worse, there is no guarantee then the write to would done Everbe observed main by, since there was no synchronizationevent s between the threads. The loop in was main Notguaranteed to finish.

There is subtler variants on this theme, such as this program.

Type T struct {msg string}var g *tfunc Setup () {t: = new (t) t.msg = "Hello, world" G = T}func main () {go setup () for g = = Nil {}print (g.msg)}

Even if main observes and g != nil exits its loop,there are no guarantee that it'll observe the initializedvalue for g.msg .

In all these examples, the solution is the Same:use explicit synchronization.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.