This is the fourth day of my participation in the November Gwen Challenge. Check out the details: The last Gwen Challenge 2021

Go memory model

Software (compiler) or hardware (CPU) systems can, based on the results of their analysis of the code, disrupt the execution order of the code to some extent, to achieve their ulterior purpose (improve CPU utilization)

  • Visibility: The GO memory model illustrates how a write by one Goroutine to a variable can be guaranteed to be detected by another Goroutine reading that variable.
  • Sequence of events: Programs that modify data accessed simultaneously by more than one Goroutine must serialize that access.

To serialize access, you need to protect data through channels, or other synchronization primitives in sync and sync/atomic packages.

What Happens Before?

define

If event E1 occurred before e2, then e2 is said to have occurred after E1. In other words, if E1 does not occur before or after E2, then e1 and E2 are said to be concurrent.

explain

In a single Goroutine, the order in which events occur is the order expressed by the program.

The compiler and processor reorder the read and write order only if it does not change the language specification’s definition of goroutine behavior.

Because of reordering, the order of execution detected by one Goroutine may be different from that detected by another. For example, if a goroutine executes a=1; b=2; , another Goroutine may detect that the value of B is first updated with a.

Single goroutine: - w0 - r1, w1, w2, r2, r3 -- -- -- -- -- - > all order of r/w is comparable. Case of double Go path:  -- w0 -- r1 -- r2 ---- w3 ---- w4 ---- r5 --------> -- w1 ----- w2 -- r3 ---- r4 ---- w5 --------> Events on a single Goroutine have a sequence; For the two Goroutines, the situation is different. Even though R1 precedes W2 in time, there is no logical order between the two because each goroutine is stretched like a rubber band. In other words, both are concurrent. For concurrent R/W, R3 may read the previous W2, the above W3, or even the value of W4; R5 may read the value of W4, w1, W2, w5, but it cannot be the value of W3. Case of double Goroutine cross synchronization: - r0 - r1 - | -- -- -- -- -- - r2 -- -- -- -- -- -- -- -- -- -- -- - | - w5 -- -- -- -- -- - > - w1 - w2 - | - r3, r4, w4 - | -- -- -- -- -- -- -- > now added two synchronous points above, Namely the |. In this case, R3 comes after R1, and before W5. R2 is written to w2 before, but is concurrent with W4, so the value of R2 is uncertain: it can be w2 or W4. R4 writes to w2 before r4 writes to w2, but does not write to it concurrently, so R4 reads w2.Copy the code

synchronous

Initialize the

The initialization of the program runs in a single Goroutine, but that Goroutine may create other goroutines that run concurrently.

If package P imports package Q, then q’s init function completes before any of p’s functions start.

The function main.main is started after all init functions have finished.

The creation of a goroutine

The GO statement starts a new Goroutine before the current goroutine starts execution.

The go statement that starts a new goroutine happens before the goroutine’s execution begins.

The action of creating a new Goroutine with the go keyword occurs before the goroutine executes.

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

The destruction of goroutine

Goroutine cannot ensure that it exits before any event in the program occurs. (Without synchronization primitive protection)

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

For example, goroutine cannot ensure that the assignment to variable A is completed before printing, because there is no synchronization event after the assignment to variable A, so there is no guarantee that it will be detected by other Goroutines (this can be solved by using channels).