Golang memory model

Source: Internet
Author: User

Ref: https://golang.org/ref/mem

    1. Brief introduction

Golang memory model , mainly describes the following issues. Reads a variable in a goroutine, and the variable is assigned by another goroutine, in which case it is safe to read correctly.

    1. Suggestions

For variables that have multiple goroutine in use , a serialized read is required for modification.

The main methods include, by means of channel, sync/atomic and other atomic synchronous operation .

If you want to read the following to understand how your program works inside, you're smart.

But I don't recommend you to be so smart.

    1. Historical experience

When there is only one goroutine , read and write operations are performed in the order defined by the program. This is because, although the compiler and the CPU are likely to change the order of execution, they do not affect the behavior logic in the Goroutine defined by the programming language. But also because it is possible to change the order of execution, the same operations observed in different goroutine are inconsistent in the order of execution. For example a Goroutine performs a=1;b=2, and another goroutine observes that B precedes a is assigned .

To specify the requirements for read and write operations, we define the following logic for the memory operations in the Golang program in a previous release. If event e1 occurs before event e2 , we say that e2 takes placeafter e 1 . If e1 does not occur before E 2 , nor does e2 occur after we say that e1 and E2 are synchronous.

In a single Goroutine program, the order in which events occur is the order in which the programs are described.

When the following two conditions are met, the read operation R for the variable v is able to observe the write operation W of V:

    1. R does not occur before W;
    2. R before, W, there is no other write operation to V;

In order to ensure that the variable v pair read operation R, the specific v write operation W can be observed, it is necessary to ensure that W is the only one observing the write operation. Therefore, to ensure that R can observe that W needs to meet the following two conditions:

    1. W occurs before R;
    2. Other writes to v occur either before W or after R;

The condition is stricter than the first condition, which requires R and W, and there is no other write operation (i.e., synchronous write operation with R or W);

In a single goroutine, there is no synchronous operation, so the above two sets of conditions are equivalent. However, for multiple goroutine, synchronization events are required to determine the order in which the read operation can be observed.

In the memory model, the variable v is initialized to a value of 0 and is also a write operation.

The action of reading and writing variables larger than a single machine code, the actual sequence of operations,

    1. Synchronous
      • Initialization

The program is initialized in a single goroutine , but Goroutine creates additional goroutine, and then multiple goroutine are executed synchronously.

If package p references the package Q, the execution of the INIT function of q will precede all functions of P.

The execution of the Main.main function is performed after all init functions have been executed.

      • Creation of Goroutine

Go expression , a goroutine is created before the goroutine can begin execution.

var string func f () {        print (a)}func hello () {        "Hello,world"        go f ( )}

For the above code example, call the Hello function, and it is possible that F will return to print after Hello has returned.

      • Destruction of Goroutine

Goroutine's exit timing is not guaranteed to be certain before an event.

var a string

Func Hello () {
Go func () {a = "Hello"} ()
Print (a)
}

For example above, the assignment of a is not guaranteed to be synchronized with any action of the hello itself, so it is not guaranteed to be observed by any other goroutine read operation. In fact, any radical compiler would simply delete the entire go expression here and not compile it.

If the influence of a goroutine is to be observed by other goroutine, the relative order relationship must be determined through synchronization mechanisms such as locks and channel.

      • Channel Communication

Channel communication is the main synchronization mode between Goroutines . In general, each send on the channel will have another goroutine message from this channel.

On the same channel, the send operation is always done before the corresponding receive operation.

var int Ten )varstringfunc f () {        "Hello,world"          0 }func Main () {        go f ()        <-C        print (a)}

The above example ensures that print "Hello, World" is available. The write to a is preceded by sending 0 in C, and receiving the value from C, prior to print.

The closing of the channel is preceded by the 0 of the channel being sent off .

In the above example , using Close (c) instead of c<-0, the effect is the same.

For channel,receive that do not have a cache, it occurs before send completes.

var int )varstringfunc f () {        "Hello,world"        <-C}func Main () {        go f ()        0        print (a)}

The above example is still guaranteed to print out "Hello, World". The writing of A is first received from C, received from C, executed before C <-0, and C <-0 is executed before print.

However, if the channel is cached (for example, C = Make (chan int, 1)), then the above procedure does not guarantee that the print "Hello, World", or even the possibility of null values, crash, etc.

For the channel with a cache capacity of C, the K-time receive is completed before the K+c .

This rule outlines the rules for caching and non-cached channel. Therefore, based on the channel with the cache, the token policy can be implemented: the number of caches in the channel represents the number of active, the buffer capacity of the channel indicates the maximum number of usable, the sending message indicates that a token was requested, and a token was released to receive the message. This is a common means of limiting concurrency.

var int 3 func Main ()        {for _, W: = Range work {                go func (w func ()) {                         1                        W ()                        <-Limit                } (w)        }        select{}}

For each of the above example programs, a goroutine is created for each of the work lists, but it is limited by the buffer channel with limit, with up to 3 goroutines at the same time. .

      • Lock mechanism

The sync package implements a data type of two locks , namely Sync. Mutexes and Sync.rwmutex

For any of the sync. The mutex and Sync.rwmutex type variables L, and N<m, for L.unlock () call n, are always preceded by a call to L.lock () m.

var l sync. Mutexvarstringfunc f () {        "Hello,world"        L . Unlock ()}func main () {        l.lock ()        go f ()        L.lock ()        print (a)}

The example above ensures that print "Hello, World" is available. the first L in F. The invocation of Unlock () precedes the second L in Main. The call to Lock (), and the second L. The call to Lock () precedes the print call;

Any for L. Rlock Call (where L is a sync.rwmutex type variable), there is always an n,L.lock can return after calling N to execute L.unlock, andl.runlock executionin call n+1 execute L . Before unlock .

      • Single case (Once)

The sync package provides a secure, multi-goroutine initialization mechanism , which is the once type . For a specific method F, multiple threads can call once. Do (f), but only one thread executes F, and calls from other threads will block until F executes.

For once. Do (f), and only one call is actually executed and executed before the other calls are returned.

var string var once sync. Oncefunc Setup () {        "Hello,world"}func doprint () {        once. Do (Setup)        print (a)}func Twoprint () {        go doprint ()        go Doprint ()}

Print two times "Hello, World" here, but only the first call to Doprint will execute the setup assignment.

    1. Incorrect synchronization

For read operations that occur synchronously R and write operation W, R is possible to observe W. However, even if this happens, it does not represent the read operation after R, and the write operation before W can be observed.

var int func f () {        1        2}func g () {        print (b)        print (a)}func main () {        go f ()        g ()}

As the example above, G prints 2, then 0. This fact overturns some of our customary perceptions .

Double check is always needed for the sync issue lock .

var a string
var done bool

Func Setup () {
A = "Hello,world"
Done = True
}

Func Doprint () {
If!done{
Once. Do (Setup)
}
Print (a)
}

Func Twoprint () {
Godoprint ()
Go Doprint ()
}

As this example does, it is not guaranteed that the write operation of a can be observed when the done write is observed. One of the goroutine may print out an empty string.

Another type of error is typically as follows:

var string var BOOL func Setup () {        "Hello,world"        true}func main () {        go setup ()        for! Done {        }        print (a)}

As in the previous example, there is no guarantee that a's write observation can be done, so it is possible to print an empty string.

Even more, because there is no synchronization event between main and setup two threads, there is no guarantee that the write operation will be observed in main, so there is no end to the loop in main. ( this is not very understandable, only that the timing of setup and the for loop in main does not have a definite relative and relative distance, so it may cause the loop to be too long, or executed but not updated to the done read by main)

There are some variants of the above styles, as follows:

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

Even if main can observe the assignment of G and exit the loop, it is not guaranteed to observethe initialization value of G. MSG .

For all of the above examples, the solution is the same, with a well-defined synchronization mechanism.

Golang memory model

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.