Go: Under the Hood Under the Hood
中文

Chapter 11 Synchronization Primitives and Patterns

The fact that the construction can be defined in terms of simpler underlying primitives is a useful guarantee that its inclusion is logically consistent with the remainder of the language.
-- C. A. R. Hoare, "Communicating Sequential Processes", 1978

In the conclusion of his CSP paper, Hoare writes that input, output and concurrency should be regarded as primitives of programming, but that this does not make them a replacement for every other concept in a language. A more elaborate construction, such as a procedure or a monitor, deserves dedicated notation if it is frequently useful, has properties that are easier to prove, and can be implemented more efficiently than the general case. Go’s choices agree with this. Channels and select are part of the language (Chapter 10); mutexes, atomic operations, condition variables and the like are provided by the standard library packages sync and sync/atomic; and what the runtime itself uses to implement a channel is a lock (10.6.5).

This chapter covers these library-level synchronization primitives. Section 11.1 revisits the two traditions of shared memory and message passing and the duality between them. Sections 11.2 through 11.8 discuss the implementation and design trade-offs of the mutex, atomic operations, the condition variable, the wait group, the object pool, the concurrency-safe hash table and the context. Section 11.9 starts from hardware and programming-language memory models and arrives at the Go memory model, which defines the visibility guarantees that these primitives and channels provide together. For when to use a channel and when to use a lock, see 10.7.