<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Chapter 11 Synchronization Primitives and Patterns on Go: Under the Hood</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/</link><description>Recent content in Chapter 11 Synchronization Primitives and Patterns on Go: Under the Hood</description><generator>Hugo</generator><language>en</language><atom:link href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/index.xml" rel="self" type="application/rss+xml"/><item><title>11.1 Shared-Memory Synchronization Patterns</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/basic/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/basic/</guid><description>&lt;h1 id="111-shared-memory-synchronization-patterns"&gt;11.1 Shared-Memory Synchronization Patterns&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;The fact that programs can be constructed from simpler basic primitives is a strong
guarantee: what these primitives contain stays logically consistent with the rest of the
programming language.
&amp;ndash; C. A. R. Hoare&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The whole difficulty of concurrent programming can be distilled into a single sentence:
multiple units of execution must cooperate over the same shared state, and the order in
which each of them makes progress cannot be predicted. How to make that cooperation both
correct and efficient has, over more than half a century, split into two great traditions.
This chapter is about one of them, shared memory. Before we take apart the concrete
primitives in Go&amp;rsquo;s standard library &lt;code&gt;sync&lt;/code&gt; and &lt;code&gt;sync/atomic&lt;/code&gt;, this section first lays the
two traditions side by side to tell them apart, explains why they are dual to each other,
and then states where Go stands between them. Once you understand this layer of trade-offs,
the sections from &lt;a href=".././mutex"&gt;11.2&lt;/a&gt; through &lt;a href=".././mem"&gt;11.9&lt;/a&gt; are no longer isolated APIs
but the same design philosophy landing on different scenarios.&lt;/p&gt;</description></item><item><title>11.2 Mutex</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mutex/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mutex/</guid><description>&lt;h1 id="112-mutex"&gt;11.2 Mutex&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;sync.Mutex&lt;/code&gt; is the most basic synchronization primitive: it lets only one goroutine enter the
critical section at a time. Beneath that plain interface, it keeps weighing two goals that pull
against each other, &lt;strong&gt;throughput&lt;/strong&gt; (hand the lock to someone as quickly as possible, do not let the
CPU sit idle) and &lt;strong&gt;fairness&lt;/strong&gt; (do not let some unlucky waiter wait in line forever). The two cannot
both be maxed out: handing the lock off in strict arrival order is the fairest, but pays a context
switch on every handoff; letting a just-woken waiter compete freely with whoever is running is the
fastest, but can leave some waiter losing out again and again. This section first lays out the theory
and the hardware foundations of the old problem of mutual exclusion, then looks at how Go&amp;rsquo;s mutex
walks this tightrope.&lt;/p&gt;</description></item><item><title>11.3 Atomic Operations</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/atomic/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/atomic/</guid><description>&lt;h1 id="113-atomic-operations"&gt;11.3 Atomic Operations&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;sync/atomic&lt;/code&gt; is the layer of Go&amp;rsquo;s synchronization primitives that sits closest to the hardware.
Higher-level tools such as the mutex (&lt;a href=".././mutex"&gt;11.1&lt;/a&gt;) and channels (&lt;a href="../ch08channel"&gt;8&lt;/a&gt;) are all
built on top of atomic operations internally. It provides &amp;ldquo;indivisible&amp;rdquo; reads, writes, and
read-modify-writes: an atomic operation either happens in full or not at all, and no other goroutine
ever sees it half-finished. But the meaning of atomic operations goes far beyond &amp;ldquo;no tearing.&amp;rdquo; It is
the foundation of lock-free programming, and behind lock-free programming lies a profound theory
about &amp;ldquo;which primitives can do what.&amp;rdquo; That theory is what this section really wants to make clear.&lt;/p&gt;</description></item><item><title>11.4 Condition Variables</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/cond/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/cond/</guid><description>&lt;h1 id="114-condition-variables"&gt;11.4 Condition Variables&lt;/h1&gt;
&lt;p&gt;The mutex (&lt;a href=".././mutex"&gt;11.2&lt;/a&gt;) answers the question of &amp;ldquo;who may enter the critical section.&amp;rdquo; A condition variable answers a different one: &amp;ldquo;a Goroutine has already entered the critical section, but finds it cannot do its work yet; how does it wait until the moment it can, while yielding the critical section to others.&amp;rdquo; The producer and consumer is the most common example. When the queue is full, the producer can neither write nor keep spinning while holding the lock, otherwise the consumer can never acquire the lock to free up space, and both sides deadlock together. The condition variable &lt;code&gt;sync.Cond&lt;/code&gt; offers this way out: let the producer &amp;ldquo;sleep with the lock,&amp;rdquo; atomically hand off the lock and block, and once the consumer frees up space, wake it back up, with the lock back in its hands on waking.&lt;/p&gt;</description></item><item><title>11.5 Wait Groups</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/waitgroup/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/waitgroup/</guid><description>&lt;h1 id="115-wait-groups"&gt;11.5 Wait Groups&lt;/h1&gt;
&lt;p&gt;The mutex (&lt;a href=".././mutex"&gt;11.2&lt;/a&gt;) and the condition variable (&lt;a href=".././cond"&gt;11.4&lt;/a&gt;) from the previous
sections solve the problem of &amp;ldquo;multiple Goroutines contending for the same shared state.&amp;rdquo; This
section turns to &lt;code&gt;sync.WaitGroup&lt;/code&gt;, which solves a different class of problem: one Goroutine spawns
several subtasks, then waits for all of them to finish before continuing. The former is contention,
the latter is rendezvous. This is one of the most common structures in concurrent programming,
called fork-join, and &lt;code&gt;WaitGroup&lt;/code&gt; is exactly the Go standard library&amp;rsquo;s answer to it.&lt;/p&gt;</description></item><item><title>11.6 Object Pool</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/pool/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/pool/</guid><description>&lt;h1 id="116-object-pool"&gt;11.6 Object Pool&lt;/h1&gt;
&lt;p&gt;Allocating and then discarding the same kind of temporary object over and over puts heavy pressure on
the garbage collector (&lt;a href="https://golang.design/under-the-hood/en/part4memory/ch13gc/"&gt;13&lt;/a&gt;). &lt;code&gt;sync.Pool&lt;/code&gt; offers a way out: stash a used object
and reuse it next time instead of allocating fresh every time. Its typical use is for temporary objects
like buffers and serializers that are &amp;ldquo;discarded after one use, yet needed again and again&amp;rdquo;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bufPool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;New&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;any&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bufPool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;().(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// the object you get back may be dirty, so reset it first&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ... use b ...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;bufPool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// put it back when done, for others to reuse&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;New&lt;/code&gt; is the only field the user needs to supply: when the pool has no object to hand out, it falls back
to &lt;code&gt;New&lt;/code&gt; to make one. So what &lt;code&gt;Get&lt;/code&gt; returns is either an old object someone just put back, or a new one
freshly made by &lt;code&gt;New&lt;/code&gt;, and the caller has no way, and no need, to tell the two apart. This section first
covers the ancient idea of reusing objects that the pool rests on, then unpacks the three layers it builds
for concurrency and GC: per-P sharding, the victim cache, and cooperation with the runtime&amp;rsquo;s GC.&lt;/p&gt;</description></item><item><title>11.7 Concurrency-Safe Hash Table</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/map/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/map/</guid><description>&lt;h1 id="117-concurrency-safe-hash-table"&gt;11.7 Concurrency-Safe Hash Table&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;sync.Map&lt;/code&gt; went through a complete internal rewrite in Go 1.24: the original
read/dirty two-map design was replaced by a concurrent hash-trie. This section first makes the
origin of each of these two generations of design clear, then places them back into the
solution lineage of concurrent hash tables.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The language&amp;rsquo;s built-in &lt;code&gt;map&lt;/code&gt; is not concurrency-safe. When multiple goroutines read and write the same &lt;code&gt;map&lt;/code&gt; simultaneously without synchronization,
the runtime actively detects the concurrent access and terminates the process with &lt;code&gt;fatal error: concurrent map read and map write&lt;/code&gt;
(&lt;a href="https://golang.design/under-the-hood/en/part2lang/ch05data/map/"&gt;5.2&lt;/a&gt; introduced this detection mechanism; it is unrecoverable, and &lt;code&gt;recover&lt;/code&gt;
cannot intercept it). For services with availability requirements, this is a design question that must be answered head-on: when multiple goroutines need to share
one table, what structure should be used.&lt;/p&gt;</description></item><item><title>11.8 Context</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/context/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/context/</guid><description>&lt;h1 id="118-context"&gt;11.8 Context&lt;/h1&gt;
&lt;p&gt;A request entering a server seldom runs to completion inside a single goroutine. It fans out into
a tree of goroutines: one queries the database, one calls a downstream RPC, one reads the cache,
and each of these spawns smaller units of work in turn. Once the originator of the request no longer
needs the result, say the client has disconnected, or the upstream has already timed out, all the
work still running across that tree becomes pure waste, holding connections, locks, and memory while
no one will ever read what it produces. The problem then becomes: &lt;strong&gt;how do we propagate the signal
&amp;ldquo;stop here&amp;rdquo; from the root of the tree out to every leaf, so each of them can stop on its own.&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>11.9 Memory Consistency Models</title><link>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mem/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mem/</guid><description>&lt;h1 id="119-memory-consistency-models"&gt;11.9 Memory Consistency Models&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Go&amp;rsquo;s memory model went through an important revision in 2022 with Go 1.19.
After laying out the current model, this section devotes space to the background of that
revision (see &lt;a href="https://golang.design/under-the-hood/en/part3concurrency/ch11sync/mem/#1198-the-evolution-of-the-design"&gt;11.9.8&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The reader may have noticed that in the earlier discussion of the Go runtime and compiler we
kept steering clear of one topic: Go&amp;rsquo;s memory model. The avoidance was not without reason. To
explain it properly requires groundwork in concurrency, synchronization primitives, and even
the hardware layer, and only now is that groundwork in place. As the close of this chapter,
and as the book&amp;rsquo;s summary of Go&amp;rsquo;s synchronization primitives and patterns, we take up the
topic here and answer the question still unresolved in the reader&amp;rsquo;s mind: when two Goroutines
read and write the same variable at once, under what conditions is one side&amp;rsquo;s write
guaranteed to be seen by the other.&lt;/p&gt;</description></item></channel></rss>