The city is so windy that lonely people always come home late

For a better reading experience, please move to the wechat official account: Golang Memory Model-1 Chan Happens Before

1. Introduction

Golang’s memory model involves a lot of things, such as memory rearrangement, L1-L3 level cache, compiler and processor, etc. It is unrealistic to explain all these things, so let’s focus on how Golang resolves happens-before.

2. It Happens Before

In a gouroutine, the reads and writes must be executed in the order in which they are in the program. That is, the compiler and processor can change the order of read and write execution only if it does not change the behavior of the Goroutine. Due to reordering, different Goroutines may see different execution orders. For example, a goroutine executes a = 1; b = 2; , another Goroutine might see B updated before A. To illustrate the conditions necessary for reading and writing, we define Happens Before -- the partial order in which memory operations are performed in a Go program. If event E1 happens before event E2, we can say that event e2 happens after event e1. If E1 doesn't happen before e2 and it doesn't happen after E2, we say e1 and E2 are concurrent. The order that precedes in a single goroutine is the order of expression in the program. A read to v r is allowed to see a write to v w if the following conditions are met: 1 r does not precede w. 2 After w, there is no other write to v before r. To ensure that a read to v r sees a write to v w, make sure that w is the only write that r is allowed to see. That is, r is guaranteed to see w when the following conditions are met: 1 w occurs first in r 2 and other writes to the shared variable V either precede w or follow r. This pair of conditions is stricter than the previous conditions and requires that no other writes occur concurrently with w or R. There is no concurrency in a separate Goroutine, so the above two definitions are the same: the read operation r sees the value of the last write operation W wrote to v. When multiple Goroutines access the shared variable v, they must use synchronous events to establish a preemptive condition to ensure that the read sees the required write. Initialization of the variable v to a zero value is represented in the memory model as a write operation. Read and write operations on variables larger than one word behave like operations on multiple variables of one word size in an indefinite order.Copy the code

Example 3.

Create a goroutine:

 a string

func f() {  
    print(a)
}
    
func hello() {
    a = "hello, world"
    go f()
}
Copy the code

The go keyword starts a new goroutine. W of a Happens Before the goroutine starts executing, and then at some point the value of A is printed. Hello, world is the r operation. This clearly satisfies our happens-before principle.

Destruction of goroutine:

a string

func hello() {
    go func() { a = "hello" }()    
    print(a)
}
Copy the code

The exit of a gouroutine does not guarantee any event that occurred in the program before, i.e. the order of w and R is not guaranteed, and it is likely to output “”, hello, etc., and the result will not be determined.

4. Solve

One of the core solutions is to leverage channels

package main var a string var c = make(chan int, 10) func hello() {go func() {a = "hello" c < -0}() <-c // wait for c to finish writing Print (a)} func main() {hello()}Copy the code

Of course, replacing c < -0 with close(c) will produce the same result, that is, output hello, you can check this, eyes thousands of times rather than hands.

5. Summary

Of course chan can be implemented without buffering, as long as you follow HappensBefore’s design principles. The solution is not unique. So that’s it for today, and next time we’ll share the role of locks and once in addressing memory models.

6. Follow public accounts

Wechat official account: Stack Future

Hope you pay attention to ha, the original is not easy, ask for praise, attention, share