diff options
Diffstat (limited to 'doc/go_mem.html')
-rw-r--r-- | doc/go_mem.html | 510 |
1 files changed, 0 insertions, 510 deletions
diff --git a/doc/go_mem.html b/doc/go_mem.html deleted file mode 100644 index a38828358..000000000 --- a/doc/go_mem.html +++ /dev/null @@ -1,510 +0,0 @@ -<!-- The Go Memory Model --> -<!-- subtitle Version of June 10, 2011 --> - -<style> -p.rule { - font-style: italic; -} -span.event { - font-style: italic; -} -</style> - -<h2>Introduction</h2> - -<p> -The Go memory model specifies the conditions under which -reads of a variable in one goroutine can be guaranteed to -observe values produced by writes to the same variable in a different goroutine. -</p> - -<h2>Happens Before</h2> - -<p> -Within a single goroutine, reads and writes must behave -as if they executed in the order specified by the program. -That is, compilers and processors may reorder the reads and writes -executed within a single goroutine only when the reordering -does not change the behavior within that goroutine -as defined by the language specification. -Because of this reordering, the execution order observed -by one goroutine may differ from the order perceived -by another. For example, if one goroutine -executes <code>a = 1; b = 2;</code>, another might observe -the updated value of <code>b</code> before the updated value of <code>a</code>. -</p> - -<p> -To specify the requirements of reads and writes, we define -<i>happens before</i>, a partial order on the execution -of memory operations in a Go program. If event <span class="event">e<sub>1</sub></span> happens -before event <span class="event">e<sub>2</sub></span>, then we say that <span class="event">e<sub>2</sub></span> happens after <span class="event">e<sub>1</sub></span>. -Also, if <span class="event">e<sub>1</sub></span> does not happen before <span class="event">e<sub>2</sub></span> and does not happen -after <span class="event">e<sub>2</sub></span>, then we say that <span class="event">e<sub>1</sub></span> and <span class="event">e<sub>2</sub></span> happen concurrently. -</p> - -<p class="rule"> -Within a single goroutine, the happens-before order is the -order expressed by the program. -</p> - -<p> -A read <span class="event">r</span> of a variable <code>v</code> is <i>allowed</i> to observe a write <span class="event">w</span> to <code>v</code> -if both of the following hold: -</p> - -<ol> -<li><span class="event">w</span> happens before <span class="event">r</span>.</li> -<li>There is no other write <span class="event">w'</span> to <code>v</code> that happens - after <span class="event">w</span> but before <span class="event">r</span>.</li> -</ol> - -<p> -To guarantee that a read <span class="event">r</span> of a variable <code>v</code> observes a -particular write <span class="event">w</span> to <code>v</code>, ensure that <span class="event">w</span> is the only -write <span class="event">r</span> is allowed to observe. -That is, <span class="event">r</span> is <i>guaranteed</i> to observe <span class="event">w</span> if both of the following hold: -</p> - -<ol> -<li><span class="event">w</span> happens before <span class="event">r</span>.</li> -<li>Any other write to the shared variable <code>v</code> -either happens before <span class="event">w</span> or after <span class="event">r</span>.</li> -</ol> - -<p> -This pair of conditions is stronger than the first pair; -it requires that there are no other writes happening -concurrently with <span class="event">w</span> or <span class="event">r</span>. -</p> - -<p> -Within a single goroutine, -there is no concurrency, so the two definitions are equivalent: -a read <span class="event">r</span> observes the value written by the most recent write <span class="event">w</span> to <code>v</code>. -When multiple goroutines access a shared variable <code>v</code>, -they must use synchronization events to establish -happens-before conditions that ensure reads observe the -desired writes. -</p> - -<p> -The initialization of variable <code>v</code> with the zero value -for <code>v</code>'s type behaves as a write in the memory model. -</p> - -<p> -Reads and writes of values larger than a single machine word -behave as multiple machine-word-sized operations in an -unspecified order. -</p> - -<h2>Synchronization</h2> - -<h3>Initialization</h3> - -<p> -Program initialization runs in a single goroutine and -new goroutines created during initialization do not -start running until initialization ends. -</p> - -<p class="rule"> -If a package <code>p</code> imports package <code>q</code>, the completion of -<code>q</code>'s <code>init</code> functions happens before the start of any of <code>p</code>'s. -</p> - -<p class="rule"> -The start of the function <code>main.main</code> happens after -all <code>init</code> functions have finished. -</p> - -<p class="rule"> -The execution of any goroutines created during <code>init</code> -functions happens after all <code>init</code> functions have finished. -</p> - -<h3>Goroutine creation</h3> - -<p class="rule"> -The <code>go</code> statement that starts a new goroutine -happens before the goroutine's execution begins. -</p> - -<p> -For example, in this program: -</p> - -<pre> -var a string - -func f() { - print(a) -} - -func hello() { - a = "hello, world" - go f() -} -</pre> - -<p> -calling <code>hello</code> will print <code>"hello, world"</code> -at some point in the future (perhaps after <code>hello</code> has returned). -</p> - -<h3>Goroutine destruction</h3> - -<p> -The exit of a goroutine is not guaranteed to happen before -any event in the program. For example, in this program: -</p> - -<pre> -var a string - -func hello() { - go func() { a = "hello" }() - print(a) -} -</pre> - -<p> -the assignment to <code>a</code> is not followed by -any synchronization event, so it is not guaranteed to be -observed by any other goroutine. -In fact, an aggressive compiler might delete the entire <code>go</code> statement. -</p> - -<p> -If the effects of a goroutine must be observed by another goroutine, -use a synchronization mechanism such as a lock or channel -communication to establish a relative ordering. -</p> - -<h3>Channel communication</h3> - -<p> -Channel communication is the main method of synchronization -between goroutines. Each send on a particular channel -is matched to a corresponding receive from that channel, -usually in a different goroutine. -</p> - -<p class="rule"> -A send on a channel happens before the corresponding -receive from that channel completes. -</p> - -<p> -This program: -</p> - -<pre> -var c = make(chan int, 10) -var a string - -func f() { - a = "hello, world" - c <- 0 -} - -func main() { - go f() - <-c - print(a) -} -</pre> - -<p> -is guaranteed to print <code>"hello, world"</code>. The write to <code>a</code> -happens before the send on <code>c</code>, which happens before -the corresponding receive on <code>c</code> completes, which happens before -the <code>print</code>. -</p> - -<p class="rule"> -The closing of a channel happens before a receive that returns a zero value -because the channel is closed. -</p> - -<p> -In the previous example, replacing -<code>c <- 0</code> with <code>close(c)</code> -yields a program with the same guaranteed behavior. -</p> - -<p class="rule"> -A receive from an unbuffered channel happens before -the send on that channel completes. -</p> - -<p> -This program (as above, but with the send and receive statements swapped and -using an unbuffered channel): -</p> - -<pre> -var c = make(chan int) -var a string - -func f() { - a = "hello, world" - <-c -} -</pre> - -<pre> -func main() { - go f() - c <- 0 - print(a) -} -</pre> - -<p> -is also guaranteed to print <code>"hello, world"</code>. The write to <code>a</code> -happens before the receive on <code>c</code>, which happens before -the corresponding send on <code>c</code> completes, which happens -before the <code>print</code>. -</p> - -<p> -If the channel were buffered (e.g., <code>c = make(chan int, 1)</code>) -then the program would not be guaranteed to print -<code>"hello, world"</code>. (It might print the empty string; -it cannot print <code>"goodbye, universe"</code>, nor can it crash.) -</p> - -<h3>Locks</h3> - -<p> -The <code>sync</code> package implements two lock data types, -<code>sync.Mutex</code> and <code>sync.RWMutex</code>. -</p> - -<p class="rule"> -For any <code>sync.Mutex</code> or <code>sync.RWMutex</code> variable <code>l</code> and <i>n</i> < <i>m</i>, -the <i>n</i>'th call to <code>l.Unlock()</code> happens before the <i>m</i>'th call to <code>l.Lock()</code> returns. -</p> - -<p> -This program: -</p> - -<pre> -var l sync.Mutex -var a string - -func f() { - a = "hello, world" - l.Unlock() -} - -func main() { - l.Lock() - go f() - l.Lock() - print(a) -} -</pre> - -<p> -is guaranteed to print <code>"hello, world"</code>. -The first call to <code>l.Unlock()</code> (in <code>f</code>) happens -before the second call to <code>l.Lock()</code> (in <code>main</code>) returns, -which happens before the <code>print</code>. -</p> - -<p class="rule"> -For any call to <code>l.RLock</code> on a <code>sync.RWMutex</code> variable <code>l</code>, -there is an <i>n</i> such that the <code>l.RLock</code> happens (returns) after the <i>n</i>'th call to -<code>l.Unlock</code> and the matching <code>l.RUnlock</code> happens -before the <i>n</i>+1'th call to <code>l.Lock</code>. -</p> - -<h3>Once</h3> - -<p> -The <code>sync</code> package provides a safe mechanism for -initialization in the presence of multiple goroutines -through the use of the <code>Once</code> type. -Multiple threads can execute <code>once.Do(f)</code> for a particular <code>f</code>, -but only one will run <code>f()</code>, and the other calls block -until <code>f()</code> has returned. -</p> - -<p class="rule"> -A single call of <code>f()</code> from <code>once.Do(f)</code> happens (returns) before any call of <code>once.Do(f)</code> returns. -</p> - -<p> -In this program: -</p> - -<pre> -var a string -var once sync.Once - -func setup() { - a = "hello, world" -} - -func doprint() { - once.Do(setup) - print(a) -} - -func twoprint() { - go doprint() - go doprint() -} -</pre> - -<p> -calling <code>twoprint</code> causes <code>"hello, world"</code> to be printed twice. -The first call to <code>twoprint</code> runs <code>setup</code> once. -</p> - -<h2>Incorrect synchronization</h2> - -<p> -Note that a read <span class="event">r</span> may observe the value written by a write <span class="event">w</span> -that happens concurrently with <span class="event">r</span>. -Even if this occurs, it does not imply that reads happening after <span class="event">r</span> -will observe writes that happened before <span class="event">w</span>. -</p> - -<p> -In this program: -</p> - -<pre> -var a, b int - -func f() { - a = 1 - b = 2 -} - -func g() { - print(b) - print(a) -} - -func main() { - go f() - g() -} -</pre> - -<p> -it can happen that <code>g</code> prints <code>2</code> and then <code>0</code>. -</p> - -<p> -This fact invalidates a few common idioms. -</p> - -<p> -Double-checked locking is an attempt to avoid the overhead of synchronization. -For example, the <code>twoprint</code> program might be -incorrectly written as: -</p> - -<pre> -var a string -var done bool - -func setup() { - a = "hello, world" - done = true -} - -func doprint() { - if !done { - once.Do(setup) - } - print(a) -} - -func twoprint() { - go doprint() - go doprint() -} -</pre> - -<p> -but there is no guarantee that, in <code>doprint</code>, observing the write to <code>done</code> -implies observing the write to <code>a</code>. This -version can (incorrectly) print an empty string -instead of <code>"hello, world"</code>. -</p> - -<p> -Another incorrect idiom is busy waiting for a value, as in: -</p> - -<pre> -var a string -var done bool - -func setup() { - a = "hello, world" - done = true -} - -func main() { - go setup() - for !done { - } - print(a) -} -</pre> - -<p> -As before, there is no guarantee that, in <code>main</code>, -observing the write to <code>done</code> -implies observing the write to <code>a</code>, so this program could -print an empty string too. -Worse, there is no guarantee that the write to <code>done</code> will ever -be observed by <code>main</code>, since there are no synchronization -events between the two threads. The loop in <code>main</code> is not -guaranteed to finish. -</p> - -<p> -There are subtler variants on this theme, such as this program. -</p> - -<pre> -type T struct { - msg string -} - -var g *T - -func setup() { - t := new(T) - t.msg = "hello, world" - g = t -} - -func main() { - go setup() - for g == nil { - } - print(g.msg) -} -</pre> - -<p> -Even if <code>main</code> observes <code>g != nil</code> and exits its loop, -there is no guarantee that it will observe the initialized -value for <code>g.msg</code>. -</p> - -<p> -In all these examples, the solution is the same: -use explicit synchronization. -</p> |