blob: d46787d14f8ed9acc3ac852247cd8ec968f40442 [file] [log] [blame]
Dirk Doughertyd5894212012-11-28 18:53:10 -08001page.title=SMP Primer for Android
2page.article=true
3@jd:body
4
5<div id="tb-wrapper">
6<div id="tb">
7<h2>In this document</h2>
8<ol class="nolist">
9 <li><a href="#theory">Theory</a>
10 <ol class="nolist">
11 <li style="margin: 3px 0 0"><a href="#mem_consistency">Memory consistency models</a>
12 <ol class="nolist">
13 <li style="margin:0"><a href="#proc_consistency">Processor consistency</a></li>
14 <li style="margin:0"><a href="#cpu_cache">CPU cache behavior</a></li>
15 <li style="margin:0"><a href="#observability">Observability</a></li>
16 <li style="margin:0"><a href="#ordering">ARM’s weak ordering</a></li>
17 </ol>
18 </li>
19 <li style="margin:3px 0 0"><a href="#datamem_barriers">Data memory barriers</a>
20 <ol class="nolist">
21 <li style="margin:0"><a href="#ss_ll">Store/store and load/load</a></li>
22 <li style="margin:0"><a href="#ls_sl">Load/store and store/load</a></li>
23 <li style="margin:0"><a href="#barrier_inst">Barrier instructions</a></li>
24 <li style="margin:0"><a href="#addr_dep">Address dependencies and causal consistency</a></li>
25 <li style="margin:0"><a href="#membarrier_summry">Memory barrier summary</a></li>
26 </ol>
27 </li>
28 <li style="margin:3px 0 0"><a href="#atomic_ops">Atomic operations</a>
29 <ol class="nolist">
30 <li style="margin:0"><a href="#atomic_essentials">Atomic essentials</a></li>
31 <li style="margin:0"><a href="#atomic_barrierpairing">Atomic + barrier pairing</a></li>
32 <li style="margin:0"><a href="#acq_rel">Acquire and release</a></li>
33 </ol>
34 </li>
35 </ol>
36 </li>
37 <li><a href="#practice">Practice</a>
38 <ol class="nolist">
39 <li style="margin:3px 0 0"><a href="#c_dont">What not to do in C</a>
40 <ol class="nolist">
41 <li style="margin:0"><a href="#volatile">C/C++ and “volatile”</a></li>
42 <li style="margin:0"><a href="#examplesc">Examples</a></li>
43 </ol>
44 </li>
45 <li style="margin:3px 0 0"><a href="#j_dont">What not to do in Java</a>
46 <ol class="nolist">
47 <li style="margin:0"><a href="#sync_volatile">“synchronized” and “volatile”</a></li>
48 <li style="margin:0"><a href="#examplesj">Examples</a></li>
49 </ol>
50 </li>
51 <li style="margin:3px 0 0"><a href="#bestpractice">What to do</a>
52 <ol class="nolist">
53 <li style="margin:0"><a href="#advice">General advice</a></li>
54 <li style="margin:0"><a href="#sync_guarantees">Synchronization primitive guarantees</a></li>
55 <li style="margin:0"><a href="#ccpp_changes">Upcoming changes to C/C++</a></li>
56 </ol>
57 </li>
58 </ol>
59 </li>
60 <li><a href="#closing_notes">Closing Notes</a></li>
61 <li><a href="#appendix">Appendix</a>
62 <ol class="nolist">
63 <li style="margin:0"><a href="#smp_failure_example">SMP failure example</a></li>
64 <li style="margin:0"><a href="#sync_stores">Implementing synchronization stores</a></li>
65 <li style="margin:0"><a href="#more">Further reading</a></li>
66 </ol>
67 </li>
68</ol>
69</div>
70</div>
71
72<p>Android 3.0 and later platform versions are optimized to support
73multiprocessor architectures. This document introduces issues that
74can arise when writing code for symmetric multiprocessor systems in C, C++, and the Java
75programming language (hereafter referred to simply as “Java” for the sake of
76brevity). It's intended as a primer for Android app developers, not as a complete
77discussion on the subject. The focus is on the ARM CPU architecture.</p>
78
79<p>If you’re in a hurry, you can skip the <a href="#theory">Theory</a> section
80and go directly to <a href="#practice">Practice</a> for best practices, but this
81is not recommended.</p>
82
83
84<h2 id="intro">Introduction</h2>
85
86<p>SMP is an acronym for “Symmetric Multi-Processor”. It describes a design in
87which two or more identical CPU cores share access to main memory. Until
88a few years ago, all Android devices were UP (Uni-Processor).</p>
89
90<p>Most &mdash; if not all &mdash; Android devices do have multiple CPUs, but generally one
91of them is used to run applications while others manage various bits of device
92hardware (for example, the radio). The CPUs may have different architectures, and the
93programs running on them can’t use main memory to communicate with each
94other.</p>
95
96<p>Most Android devices sold today are built around SMP designs,
97making things a bit more complicated for software developers. The sorts of race
98conditions you might encounter in a multi-threaded program are much worse on SMP
99when two or more of your threads are running simultaneously on different cores.
100What’s more, SMP on ARM is more challenging to work with than SMP on x86. Code
101that has been thoroughly tested on x86 may break badly on ARM.</p>
102
103<p>The rest of this document will explain why, and tell you what you need to do
104to ensure that your code behaves correctly.</p>
105
106
107<h2 id="theory">Theory</h2>
108
109<p>This is a high-speed, glossy overview of a complex subject. Some areas will
110be incomplete, but none of it should be misleading or wrong.</p>
111
112<p>See <a href="#more">Further reading</a> at the end of the document for
113pointers to more thorough treatments of the subject.</p>
114
115<h3 id="mem_consistency">Memory consistency models</h3>
116
117<p>Memory consistency models, or often just “memory models”, describe the
118guarantees the hardware architecture makes about memory accesses. For example,
119if you write a value to address A, and then write a value to address B, the
120model might guarantee that every CPU core sees those writes happen in that
121order.</p>
122
123<p>The model most programmers are accustomed to is <em>sequential
124consistency</em>, which is described like this <span
125style="font-size:.9em;color:#777">(<a href="#more" style="color:#777">Adve &
126Gharachorloo</a>)</span>:</p>
127
128<ul>
129<li>All memory operations appear to execute one at a time</li>
130<li>All operations on a single processor appear to execute in the order described
131by that processor's program.</li>
132</ul>
133
134<p>If you look at a bit of code and see that it does some reads and writes from
135memory, on a sequentially-consistent CPU architecture you know that the code
136will do those reads and writes in the expected order. It’s possible that the
137CPU is actually reordering instructions and delaying reads and writes, but there
138is no way for code running on the device to tell that the CPU is doing anything
139other than execute instructions in a straightforward manner. (We’re ignoring
140memory-mapped device driver I/O for the moment.)</p>
141
142<p>To illustrate these points it’s useful to consider small snippets of code,
143commonly referred to as <em>litmus tests</em>. These are assumed to execute in
144<em>program order</em>, that is, the order in which the instructions appear here is
145the order in which the CPU will execute them. We don’t want to consider
146instruction reordering performed by compilers just yet.</p>
147
148<p>Here’s a simple example, with code running on two threads:</p>
149
150<table>
151<tr>
152<th>Thread 1</th>
153<th>Thread 2</th>
154</tr>
155<tr>
156<td><code>A = 3<br />
157B = 5</code></td>
158<td><code>reg0 = B<br />
159reg1 = A</code></td>
160</tr>
161</table>
162
163<p>In this and all future litmus examples, memory locations are represented by
164capital letters (A, B, C) and CPU registers start with “reg”. All memory is
165initially zero. Instructions are executed from top to bottom. Here, thread 1
166stores the value 3 at location A, and then the value 5 at location B. Thread 2
167loads the value from location B into reg0, and then loads the value from
168location A into reg1. (Note that we’re writing in one order and reading in
169another.)</p>
170
171<p>Thread 1 and thread 2 are assumed to execute on different CPU cores. You
172should <strong>always</strong> make this assumption when thinking about
173multi-threaded code.</p>
174
175<p>Sequential consistency guarantees that, after both threads have finished
176executing, the registers will be in one of the following states:</p>
177
178
179<table>
180<tr>
181<th>Registers</th>
182<th>States</th>
183</tr>
184<tr>
185<td>reg0=5, reg1=3</td>
186<td>possible (thread 1 ran first)</td>
187</tr>
188<tr>
189<td>reg0=0, reg1=0</td>
190<td>possible (thread 2 ran first)</td>
191</tr>
192<tr>
193<td>reg0=0, reg1=3</td>
194<td>possible (concurrent execution)</td>
195</tr>
196<tr>
197<td>reg0=5, reg1=0</td>
198<td>never</td>
199</tr>
200</table>
201
202<p>To get into a situation where we see B=5 before we see the store to A, either
203the reads or the writes would have to happen out of order. On a
204sequentially-consistent machine, that can’t happen.</p>
205
206<p>Most uni-processors, including x86 and ARM, are sequentially consistent.
207Most SMP systems, including x86 and ARM, are not.</p>
208
209<h4 id="proc_consistency">Processor consistency</h4>
210
211<p>x86 SMP provides <em>processor consistency</em>, which is slightly weaker than
212sequential. While the architecture guarantees that loads are not reordered with
213respect to other loads, and stores are not reordered with respect to other
214stores, it does not guarantee that a store followed by a load will be observed
215in the expected order.</p>
216
217<p>Consider the following example, which is a piece of Dekker’s Algorithm for
218mutual exclusion:</p>
219
220<table>
221<tr>
222<th>Thread 1</th>
223<th>Thread 2</th>
224</tr>
225<tr>
226<td><code>A = true<br />
227reg1 = B<br />
228if (reg1 == false)<br />
229&nbsp;&nbsp;&nbsp;&nbsp;<em>critical-stuff</em></code></td>
230<td><code>B = true<br />
231reg2 = A<br />
232if (reg2 == false)<br />
233&nbsp;&nbsp;&nbsp;&nbsp;<em>critical-stuff</em></code></td>
234</tr>
235</table>
236
237<p>The idea is that thread 1 uses A to indicate that it’s busy, and thread 2
238uses B. Thread 1 sets A and then checks to see if B is set; if not, it can
239safely assume that it has exclusive access to the critical section. Thread 2
240does something similar. (If a thread discovers that both A and B are set, a
241turn-taking algorithm is used to ensure fairness.)</p>
242
243<p>On a sequentially-consistent machine, this works correctly. On x86 and ARM
244SMP, the store to A and the load from B in thread 1 can be “observed” in a
245different order by thread 2. If that happened, we could actually appear to
246execute this sequence (where blank lines have been inserted to highlight the
247apparent order of operations):</p>
248
249<table>
250<tr>
251<th>Thread 1</th>
252<th>Thread 2</th>
253</tr>
254<tr>
255<td><code>reg1 = B<br />
256<br />
257<br />
258A = true<br />
259if (reg1 == false)<br />
260&nbsp;&nbsp;&nbsp;&nbsp;<em>critical-stuff</em></code></td>
261
262<td><code><br />
263B = true<br />
264reg2 = A<br />
265<br />
266if (reg2 == false)<br />
267&nbsp;&nbsp;&nbsp;&nbsp;<em>critical-stuff</em></code></td>
268</tr>
269</table>
270
271<p>This results in both reg1 and reg2 set to “false”, allowing the threads to
272execute code in the critical section simultaneously. To understand how this can
273happen, it’s useful to know a little about CPU caches.</p>
274
275<h4 id="cpu_cache">CPU cache behavior</h4>
276
277<p>This is a substantial topic in and of itself. An extremely brief overview
278follows. (The motivation for this material is to provide some basis for
279understanding why SMP systems behave as they do.)</p>
280
281<p>Modern CPUs have one or more caches between the processor and main memory.
282These are labeled L1, L2, and so on, with the higher numbers being successively
283“farther” from the CPU. Cache memory adds size and cost to the hardware, and
284increases power consumption, so the ARM CPUs used in Android devices typically
285have small L1 caches and little or no L2/L3.</p>
286
287<p>Loading or storing a value into the L1 cache is very fast. Doing the same to
288main memory can be 10-100x slower. The CPU will therefore try to operate out of
289the cache as much as possible. The <em>write policy</em> of a cache determines when data
290written to it is forwarded to main memory. A <em>write-through</em> cache will initiate
291a write to memory immediately, while a <em>write-back</em> cache will wait until it runs
292out of space and has to evict some entries. In either case, the CPU will
293continue executing instructions past the one that did the store, possibly
294executing dozens of them before the write is visible in main memory. (While the
295write-through cache has a policy of immediately forwarding the data to main
296memory, it only <strong>initiates</strong> the write. It does not have to wait
297for it to finish.)</p>
298
299<p>The cache behavior becomes relevant to this discussion when each CPU core has
300its own private cache. In a simple model, the caches have no way to interact
301with each other directly. The values held by core #1’s cache are not shared
302with or visible to core #2’s cache except as loads or stores from main memory.
303The long latencies on memory accesses would make inter-thread interactions
304sluggish, so it’s useful to define a way for the caches to share data. This
305sharing is called <em>cache coherency</em>, and the coherency rules are defined
306by the CPU architecture’s <em>cache consistency model</em>.</p>
307
308<p>With that in mind, let’s return to the Dekker example. When core 1 executes
309“A = 1”, the value gets stored in core 1’s cache. When core 2 executes “if (A
310== 0)”, it might read from main memory or it might read from core 2’s cache;
311either way it won’t see the store performed by core 1. (“A” could be in core
3122’s cache because of a previous load from “A”.)</p>
313
314<p>For the memory consistency model to be sequentially consistent, core 1 would
315have to wait for all other cores to be aware of “A = 1” before it could execute
316“if (B == 0)” (either through strict cache coherency rules, or by disabling the
317caches entirely so everything operates out of main memory). This would impose a
318performance penalty on every store operation. Relaxing the rules for the
319ordering of stores followed by loads improves performance but imposes a burden
320on software developers.</p>
321
322<p>The other guarantees made by the processor consistency model are less
323expensive to make. For example, to ensure that memory writes are not observed
324out of order, it just needs to ensure that the stores are published to other
325cores in the same order that they were issued. It doesn’t need to wait for
326store #1 to <strong>finish</strong> being published before it can start on store
327#2, it just needs to ensure that it doesn’t finish publishing #2 before it
328finishes publishing #1. This avoids a performance bubble.</p>
329
330<p>Relaxing the guarantees even further can provide additional opportunities for
331CPU optimization, but creates more opportunities for code to behave in ways the
332programmer didn’t expect.</p>
333
334<p>One additional note: CPU caches don’t operate on individual bytes. Data is
335read or written as <em>cache lines</em>; for many ARM CPUs these are 32 bytes. If you
336read data from a location in main memory, you will also be reading some adjacent
337values. Writing data will cause the cache line to be read from memory and
338updated. As a result, you can cause a value to be loaded into cache as a
339side-effect of reading or writing something nearby, adding to the general aura
340of mystery.</p>
341
342<h4 id="observability">Observability</h4>
343
344<p>Before going further, it’s useful to define in a more rigorous fashion what
345is meant by “observing” a load or store. Suppose core 1 executes “A = 1”. The
346store is <em>initiated</em> when the CPU executes the instruction. At some
347point later, possibly through cache coherence activity, the store is
348<em>observed</em> by core 2. In a write-through cache it doesn’t really
349<em>complete</em> until the store arrives in main memory, but the memory
350consistency model doesn’t dictate when something completes, just when it can be
351<em>observed</em>.</p>
352
353
354<p>(In a kernel device driver that accesses memory-mapped I/O locations, it may
355be very important to know when things actually complete. We’re not going to go
356into that here.)</p>
357
358<p>Observability may be defined as follows:</p>
359
360<ul>
361<li>"A write to a location in memory is said to be observed by an observer Pn
362when a subsequent read of the location by Pn would return the value written by
363the write."</li>
364<li>"A read of a location in memory is said to be observed by an observer Pm
365when a subsequent write to the location by Pm would have no effect on the value
366returned by the read." <span style="font-size:.9em;color:#777">(<em><a
367href="#more" style="color:#777">Reasoning about the ARM weakly consistent memory
368model</a></em>)</span></li>
369</ul>
370
371
372<p>A less formal way to describe it (where “you” and “I” are CPU cores) would be:</p>
373
374<ul>
375<li>I have observed your write when I can read what you wrote</li>
376<li>I have observed your read when I can no longer affect the value you read</li>
377</ul>
378
379<p>The notion of observing a write is intuitive; observing a read is a bit less
380so (don’t worry, it grows on you).</p>
381
382<p>With this in mind, we’re ready to talk about ARM.</p>
383
384<h4 id="ordering">ARM's weak ordering</h4>
385
386<p>ARM SMP provides weak memory consistency guarantees. It does not guarantee that
387loads or stores are ordered with respect to each other.</p>
388
389<table>
390<tr>
391<th>Thread 1</th>
392<th>Thread 2</th>
393</tr>
394<tr>
395<td><code>A = 41<br />
396B = 1 // “A is ready”</code></td>
397<td><code>loop_until (B == 1)<br />
398reg = A</code></td>
399</tr>
400</table>
401
402<p>Recall that all addresses are initially zero. The “loop_until” instruction
403reads B repeatedly, looping until we read 1 from B. The idea here is that
404thread 2 is waiting for thread 1 to update A. Thread 1 sets A, and then sets B
405to 1 to indicate data availability.</p>
406
407<p>On x86 SMP, this is guaranteed to work. Thread 2 will observe the stores
408made by thread 1 in program order, and thread 1 will observe thread 2’s loads in
409program order.</p>
410
411<p>On ARM SMP, the loads and stores can be observed in any order. It is
412possible, after all the code has executed, for reg to hold 0. It’s also
413possible for it to hold 41. Unless you explicitly define the ordering, you
414don’t know how this will come out.</p>
415
416<p>(For those with experience on other systems, ARM’s memory model is equivalent
417to PowerPC in most respects.)</p>
418
419
420<h3 id="datamem_barriers">Data memory barriers</h3>
421
422<p>Memory barriers provide a way for your code to tell the CPU that memory
423access ordering matters. ARM/x86 uniprocessors offer sequential consistency,
424and thus have no need for them. (The barrier instructions can be executed but
425aren’t useful; in at least one case they’re hideously expensive, motivating
426separate builds for SMP targets.)</p>
427
428<p>There are four basic situations to consider:</p>
429
430<ol>
431<li>store followed by another store</li>
432<li>load followed by another load</li>
433<li>load followed by store</li>
434<li>store followed by load</li>
435</ol>
436
437<h4 id="ss_ll">Store/store and load/load</h4>
438
439<p>Recall our earlier example:</p>
440
441<table>
442<tr>
443<th>Thread 1</th>
444<th>Thread 2</th>
445</tr>
446<tr>
447<td><code>A = 41<br />
448B = 1 // “A is ready”</code></td>
449<td><code>loop_until (B == 1)<br />
450reg = A</code></td>
451</tr>
452</table>
453
454
455<p>Thread 1 needs to ensure that the store to A happens before the store to B.
456This is a “store/store” situation. Similarly, thread 2 needs to ensure that the
457load of B happens before the load of A; this is a load/load situation. As
458mentioned earlier, the loads and stores can be observed in any order.</p>
459
460<div style="padding:.5em 2em;">
461<div style="border-left:4px solid #ccc;padding:0 1em;font-style:italic;">
462<p>Going back to the cache discussion, assume A and B are on separate cache
463lines, with minimal cache coherency. If the store to A stays local but the
464store to B is published, core 2 will see B=1 but won’t see the update to A. On
465the other side, assume we read A earlier, or it lives on the same cache line as
466something else we recently read. Core 2 spins until it sees the update to B,
467then loads A from its local cache, where the value is still zero.</p>
468</div>
469</div>
470
471<p>We can fix it like this:</p>
472
473<table>
474<tr>
475<th>Thread 1</th>
476<th>Thread 2</th>
477</tr>
478<tr>
479<td><code>A = 41<br />
480<em>store/store barrier</em><br />
481B = 1 // “A is ready”</code></td>
482<td><code>loop_until (B == 1)<br />
483<em>load/load barrier</em><br />
484reg = A</code></td>
485</tr>
486</table>
487
488<p>The store/store barrier guarantees that <strong>all observers</strong> will
489observe the write to A before they observe the write to B. It makes no
490guarantees about the ordering of loads in thread 1, but we don’t have any of
491those, so that’s okay. The load/load barrier in thread 2 makes a similar
492guarantee for the loads there.</p>
493
494<p>Since the store/store barrier guarantees that thread 2 observes the stores in
495program order, why do we need the load/load barrier in thread 2? Because we
496also need to guarantee that thread 1 observes the loads in program order.</p>
497
498<div style="padding:.5em 2em;">
499<div style="border-left:4px solid #ccc;padding:0 1em;font-style:italic;">
500<p>The store/store barrier could work by flushing all
501dirty entries out of the local cache, ensuring that other cores see them before
502they see any future stores. The load/load barrier could purge the local cache
503completely and wait for any “in-flight” loads to finish, ensuring that future
504loads are observed after previous loads. What the CPU actually does doesn’t
505matter, so long as the appropriate guarantees are kept. If we use a barrier in
506core 1 but not in core 2, core 2 could still be reading A from its local
507cache.</p>
508</div>
509</div>
510
511<p>Because the architectures have different memory models, these barriers are
512required on ARM SMP but not x86 SMP.</p>
513
514<h4 id="ls_sl">Load/store and store/load</h4>
515
516<p>The Dekker’s Algorithm fragment shown earlier illustrated the need for a
517store/load barrier. Here’s an example where a load/store barrier is
518required:</p>
519
520<table>
521<tr>
522<th>Thread 1</th>
523<th>Thread 2</th>
524</tr>
525<tr>
526<td><code>reg = A<br />
527B = 1 // “I have latched A”</code></td>
528<td><code>loop_until (B == 1)<br />
529A = 41 // update A</code></td>
530</tr>
531</table>
532
533<p>Thread 2 could observe thread 1’s store of B=1 before it observe’s thread 1’s
534load from A, and as a result store A=41 before thread 1 has a chance to read A.
535Inserting a load/store barrier in each thread solves the problem:</p>
536
537<table>
538<tr>
539<th>Thread 1</th>
540<th>Thread 2</th>
541</tr>
542<tr>
543<td><code>reg = A<br />
544<em>load/store barrier</em><br />
545B = 1 // “I have latched A”</code></td>
546<td><code>loop_until (B == 1)<br />
547<em>load/store barrier</em><br />
548A = 41 // update A</code></td>
549</tr>
550</table>
551
552<div style="padding:.5em 2em;">
553<div style="border-left:4px solid #ccc;padding:0 1em;font-style:italic;">
554<p>A store to local cache may be observed before a load from main memory,
555because accesses to main memory are so much slower. In this case, assume core
5561’s cache has the cache line for B but not A. The load from A is initiated, and
557while that’s in progress execution continues. The store to B happens in local
558cache, and by some means becomes available to core 2 while the load from A is
559still in progress. Thread 2 is able to exit the loop before it has observed
560thread 1’s load from A.</p>
561
562<p>A thornier question is: do we need a barrier in thread 2? If the CPU doesn’t
563perform speculative writes, and doesn’t execute instructions out of order, can
564thread 2 store to A before thread 1’s read if thread 1 guarantees the load/store
565ordering? (Answer: no.) What if there’s a third core watching A and B?
566(Answer: now you need one, or you could observe B==0 / A==41 on the third core.)
567 It’s safest to insert barriers in both places and not worry about the
568details.</p>
569</div>
570</div>
571
572<p>As mentioned earlier, store/load barriers are the only kind required on x86
573SMP.</p>
574
575<h4 id="barrier_inst">Barrier instructions</h4>
576
577<p>Different CPUs provide different flavors of barrier instruction. For
578example:</p>
579
580<ul>
581<li>Sparc V8 has a “membar” instruction that takes a 4-element bit vector. The
582four categories of barrier can be specified individually.</li>
583<li>Alpha provides “rmb” (load/load), “wmb” (store/store), and “mb” (full).
584(Trivia: the linux kernel provides three memory barrier functions with these
585names and behaviors.)</li>
586<li>x86 has a variety of options; “mfence” (introduced with SSE2) provides a
587full barrier.</li>
588<li>ARMv7 has “dmb st” (store/store) and “dmb sy” (full).</li>
589</ul>
590
591<p>“Full barrier” means all four categories are included.</p>
592
593<p>It is important to recognize that the only thing guaranteed by barrier
594instructions is ordering. Do not treat them as cache coherency “sync points” or
595synchronous “flush” instructions. The ARM “dmb” instruction has no direct
596effect on other cores. This is important to understand when trying to figure
597out where barrier instructions need to be issued.</p>
598
599
600<h4 id="addr_dep">Address dependencies and causal consistency</h4>
601
602<p><em>(This is a slightly more advanced topic and can be skipped.)</em>
603
604<p>The ARM CPU provides one special case where a load/load barrier can be
605avoided. Consider the following example from earlier, modified slightly:</p>
606
607<table>
608<tr>
609<th>Thread 1</th>
610<th>Thread 2</th>
611</tr>
612<tr>
613<td><code>[A+8] = 41<br />
614<em>store/store barrier</em><br />
615B = 1 // “A is ready”</code></td>
616<td><code>loop:<br />
617&nbsp;&nbsp;&nbsp;&nbsp;reg0 = B<br />
618&nbsp;&nbsp;&nbsp;&nbsp;if (reg0 == 0) goto loop<br />
619reg1 = 8<br />
620reg2 = [A + reg1]</code></td>
621</tr>
622</table>
623
624<p>This introduces a new notation. If “A” refers to a memory address, “A+n”
625refers to a memory address offset by 8 bytes from A. If A is the base address
626of an object or array, [A+8] could be a field in the object or an element in the
627array.</p>
628
629<p>The “loop_until” seen in previous examples has been expanded to show the load
630of B into reg0. reg1 is assigned the numeric value 8, and reg2 is loaded from
Andy McFadden9b6687b2013-01-15 12:26:04 -0800631the address [A+reg1] (the same location that thread 1 is accessing).</p>
Dirk Doughertyd5894212012-11-28 18:53:10 -0800632
633<p>This will not behave correctly because the load from B could be observed
634after the load from [A+reg1]. We can fix this with a load/load barrier after
635the loop, but on ARM we can also just do this:</p>
636
637<table>
638<tr>
639<th>Thread 1</th>
640<th>Thread 2</th>
641</tr>
642<tr>
Andy McFadden9b6687b2013-01-15 12:26:04 -0800643<td><code>[A+8] = 41<br />
Dirk Doughertyd5894212012-11-28 18:53:10 -0800644<em>store/store barrier</em><br />
645B = 1 // “A is ready”</code></td>
646<td><code>loop:<br />
647&nbsp;&nbsp;&nbsp;&nbsp;reg0 = B<br />
648&nbsp;&nbsp;&nbsp;&nbsp;if (reg0 == 0) goto loop<br />
649reg1 = 8 <strong>+ (reg0 & 0)</strong><br />
650reg2 = [A + reg1]</code></td>
651</tr>
652</table>
653
654<p>What we’ve done here is change the assignment of reg1 from a constant (8) to
655a value that depends on what we loaded from B. In this case, we do a bitwise
656AND of the value with 0, which yields zero, which means reg1 still has the value
6578. However, the ARM CPU believes that the load from [A+reg1] depends upon the
658load from B, and will ensure that the two are observed in program order.</p>
659
660<p>This is called an <em>address dependency</em>. Address dependencies exist
661when the value returned by a load is used to compute the address of a subsequent
662load or store. It can let you avoid the need for an explicit barrier in certain
663situations.</p>
664
665<p>ARM does not provide <em>control dependency</em> guarantees. To illustrate
666this it’s necessary to dip into ARM code for a moment: <span
667style="font-size:.9em;color:#777">(<em><a href="#more"
668style="color:#777">Barrier Litmus Tests and Cookbook</a></em>)</span>.</p>
669
670<pre>
671LDR r1, [r0]
672CMP r1, #55
673LDRNE r2, [r3]
674</pre>
675
676<p>The loads from r0 and r3 may be observed out of order, even though the load
677from r3 will not execute at all if [r0] doesn’t hold 55. Inserting AND r1, r1,
678#0 and replacing the last instruction with LDRNE r2, [r3, r1] would ensure
679proper ordering without an explicit barrier. (This is a prime example of why
680you can’t think about consistency issues in terms of instruction execution.
681Always think in terms of memory accesses.)</p>
682
683<p>While we’re hip-deep, it’s worth noting that ARM does not provide <em>causal
684consistency</em>:</p>
685
686<table>
687<tr>
688<th>Thread 1</th>
689<th>Thread 2</th>
690<th>Thread 3</th>
691</tr>
692<tr>
693<td><code>A = 1</code></td>
694<td><code>loop_until (A == 1)<br />
695B = 1</code></td>
696<td><code>loop:<br />
697&nbsp;&nbsp;reg0 = B<br />
698&nbsp;&nbsp;if (reg0 == 0) goto loop<br />
699reg1 = reg0 & 0<br />
700reg2 = [A+reg1]</code></td>
701</tr>
702</table>
703
704<p>Here, thread 1 sets A, signaling thread 2. Thread 2 sees that and sets B to
705signal thread 3. Thread 3 sees it and loads from A, using an address dependency
706to ensure that the load of B and the load of A are observed in program
707order.</p>
708
709<p>It’s possible for reg2 to hold zero at the end of this. The fact that a
710store in thread 1 causes something to happen in thread 2 which causes something
711to happen in thread 3 does not mean that thread 3 will observe the stores in
712that order. (Inserting a load/store barrier in thread 2 fixes this.)</p>
713
714<h4 id="membarrier_summary">Memory barrier summary</h4>
715
716<p>Barriers come in different flavors for different situations. While there can
717be performance advantages to using exactly the right barrier type, there are
718code maintenance risks in doing so &mdash; unless the person updating the code
719fully understands it, they might introduce the wrong type of operation and cause
720a mysterious breakage. Because of this, and because ARM doesn’t provide a wide
721variety of barrier choices, many atomic primitives use full
722barrier instructions when a barrier is required.</p>
723
724<p>The key thing to remember about barriers is that they define ordering. Don’t
725think of them as a “flush” call that causes a series of actions to happen.
726Instead, think of them as a dividing line in time for operations on the current
727CPU core.</p>
728
729
730<h3 id="atomic_ops">Atomic operations</h3>
731
732<p>Atomic operations guarantee that an operation that requires a series of steps
733always behaves as if it were a single operation. For example, consider a
734non-atomic increment (“++A”) executed on the same variable by two threads
735simultaneously:</p>
736
737<table>
738<tr>
739<th>Thread 1</th>
740<th>Thread 2</th>
741</tr>
742<tr>
743<td><code>reg = A<br />
744reg = reg + 1<br />
745A = reg</code></td>
746<td><code>reg = A<br />
747reg = reg + 1<br />
748A = reg</code></td>
749</tr>
750</table>
751
752<p>If the threads execute concurrently from top to bottom, both threads will
753load 0 from A, increment it to 1, and store it back, leaving a final result of
7541. If we used an atomic increment operation, you would be guaranteed that the
755final result will be 2.</p>
756
757<h4 id="atomic_essentials">Atomic essentials</h4>
758
759<p>The most fundamental operations &mdash; loading and storing 32-bit values
760&mdash; are inherently atomic on ARM so long as the data is aligned on a 32-bit
761boundary. For example:</p>
762
763<table>
764<tr>
765<th>Thread 1</th>
766<th>Thread 2</th>
767</tr>
768<tr>
769<td><code>reg = 0x00000000<br />
770A = reg</code></td>
771<td><code>reg = 0xffffffff<br />
772A = reg</code></td>
773</tr>
774</table>
775
776<p>The CPU guarantees that A will hold 0x00000000 or 0xffffffff. It will never
777hold 0x0000ffff or any other partial “mix” of bytes.</p>
778
779<div style="padding:.5em 2em;">
780<div style="border-left:4px solid #ccc;padding:0 1em;font-style:italic;">
781<p>The atomicity guarantee is lost if the data isn’t aligned. Misaligned data
782could straddle a cache line, so other cores could see the halves update
783independently. Consequently, the ARMv7 documentation declares that it provides
784“single-copy atomicity” for all byte accesses, halfword accesses to
785halfword-aligned locations, and word accesses to word-aligned locations.
786Doubleword (64-bit) accesses are <strong>not</strong> atomic, unless the
787location is doubleword-aligned and special load/store instructions are used.
788This behavior is important to understand when multiple threads are performing
789unsynchronized updates to packed structures or arrays of primitive types.</p>
790</div>
791</div>
792
793<p>There is no need for 32-bit “atomic read” or “atomic write” functions on ARM
794or x86. Where one is provided for completeness, it just does a trivial load or
795store.</p>
796
797<p>Operations that perform more complex actions on data in memory are
798collectively known as <em>read-modify-write</em> (RMW) instructions, because
799they load data, modify it in some way, and write it back. CPUs vary widely in
800how these are implemented. ARM uses a technique called “Load Linked / Store
801Conditional”, or LL/SC.</p>
802
803<div style="padding:.5em 2em;">
804<div style="border-left:4px solid #ccc;padding:0 1em;font-style:italic;">
805<p>A <em>linked</em> or <em>locked</em> load reads the data from memory as
806usual, but also establishes a reservation, tagging the physical memory address.
807The reservation is cleared when another core tries to write to that address. To
808perform an LL/SC, the data is read with a reservation, modified, and then a
809conditional store instruction is used to try to write the data back. If the
810reservation is still in place, the store succeeds; if not, the store will fail.
811Atomic functions based on LL/SC usually loop, retrying the entire
812read-modify-write sequence until it completes without interruption.</p>
813</div>
814</div>
815
816<p>It’s worth noting that the read-modify-write operations would not work
817correctly if they operated on stale data. If two cores perform an atomic
818increment on the same address, and one of them is not able to see what the other
819did because each core is reading and writing from local cache, the operation
820won’t actually be atomic. The CPU’s cache coherency rules ensure that the
821atomic RMW operations remain atomic in an SMP environment.</p>
822
823<p>This should not be construed to mean that atomic RMW operations use a memory
824barrier. On ARM, atomics have no memory barrier semantics. While a series of
825atomic RMW operations on a single address will be observed in program order by
826other cores, there are no guarantees when it comes to the ordering of atomic and
827non-atomic operations.</p>
828
829<p>It often makes sense to pair barriers and atomic operations together. The
830next section describes this in more detail.</p>
831
832<h4 id="atomic_barrierpairing">Atomic + barrier pairing</h4>
833
834<p>As usual, it’s useful to illuminate the discussion with an example. We’re
835going to consider a basic mutual-exclusion primitive called a <em>spin
836lock</em>. The idea is that a memory address (which we’ll call “lock”)
837initially holds zero. When a thread wants to execute code in the critical
838section, it sets the lock to 1, executes the critical code, and then changes it
839back to zero when done. If another thread has already set the lock to 1, we sit
840and spin until the lock changes back to zero.</p>
841
842<p>To make this work we use an atomic RMW primitive called
843<em>compare-and-swap</em>. The function takes three arguments: the memory
844address, the expected current value, and the new value. If the value currently
845in memory matches what we expect, it is replaced with the new value, and the old
846value is returned. If the current value is not what we expect, we don’t change
847anything. A minor variation on this is called <em>compare-and-set</em>; instead
848of returning the old value it returns a boolean indicating whether the swap
849succeeded. For our needs either will work, but compare-and-set is slightly
850simpler for examples, so we use it and just refer to it as “CAS”.</p>
851
852<p>The acquisition of the spin lock is written like this (using a C-like
853language):</p>
854
855<pre>do {
856 success = atomic_cas(&lock, 0, 1)
857} while (!success)
858
859full_memory_barrier()
860
861<em>critical-section</em></pre>
862
863<p>If no thread holds the lock, the lock value will be 0, and the CAS operation
864will set it to 1 to indicate that we now have it. If another thread has it, the
865lock value will be 1, and the CAS operation will fail because the expected
866current value does not match the actual current value. We loop and retry.
867(Note this loop is on top of whatever loop the LL/SC code might be doing inside
868the atomic_cas function.)</p>
869
870<div style="padding:.5em 2em;">
871<div style="border-left:4px solid #ccc;padding:0 1em;font-style:italic;">
872<p>On SMP, a spin lock is a useful way to guard a small critical section. If we
873know that another thread is going to execute a handful of instructions and then
874release the lock, we can just burn a few cycles while we wait our turn.
875However, if the other thread happens to be executing on the same core, we’re
876just wasting time because the other thread can’t make progress until the OS
877schedules it again (either by migrating it to a different core or by preempting
878us). A proper spin lock implementation would optimistically spin a few times
879and then fall back on an OS primitive (such as a Linux futex) that allows the
880current thread to sleep while waiting for the other thread to finish up. On a
881uniprocessor you never want to spin at all. For the sake of brevity we’re
882ignoring all this.</p>
883</div>
884</div>
885
886<p>The memory barrier is necessary to ensure that other threads observe the
887acquisition of the lock before they observe any loads or stores in the critical
888section. Without that barrier, the memory accesses could be observed while the
889lock is not held.</p>
890
891<p>The <code>full_memory_barrier</code> call here actually does
892<strong>two</strong> independent operations. First, it issues the CPU’s full
893barrier instruction. Second, it tells the compiler that it is not allowed to
894reorder code around the barrier. That way, we know that the
895<code>atomic_cas</code> call will be executed before anything in the critical
896section. Without this <em>compiler reorder barrier</em>, the compiler has a
897great deal of freedom in how it generates code, and the order of instructions in
898the compiled code might be much different from the order in the source code.</p>
899
900<p>Of course, we also want to make sure that none of the memory accesses
901performed in the critical section are observed after the lock is released. The
902full version of the simple spin lock is:</p>
903
904<pre>do {
905 success = atomic_cas(&lock, 0, 1) // acquire
906} while (!success)
907full_memory_barrier()
908
909<em>critical-section</em>
910
911full_memory_barrier()
912atomic_store(&lock, 0) // release</pre>
913
914<p>We perform our second CPU/compiler memory barrier immediately
915<strong>before</strong> we release the lock, so that loads and stores in the
916critical section are observed before the release of the lock.</p>
917
918<p>As mentioned earlier, the <code>atomic_store</code> operation is a simple
919assignment on ARM and x86. Unlike the atomic RMW operations, we don’t guarantee
920that other threads will see this value immediately. This isn’t a problem,
921though, because we only need to keep the other threads <strong>out</strong>. The
922other threads will stay out until they observe the store of 0. If it takes a
923little while for them to observe it, the other threads will spin a little
924longer, but we will still execute code correctly.</p>
925
926<p>It’s convenient to combine the atomic operation and the barrier call into a
927single function. It also provides other advantages, which will become clear
928shortly.</p>
929
930
931<h4 id="acq_rel">Acquire and release</h4>
932
933<p>When acquiring the spinlock, we issue the atomic CAS and then the barrier.
934When releasing the spinlock, we issue the barrier and then the atomic store.
935This inspires a particular naming convention: operations followed by a barrier
936are “acquiring” operations, while operations preceded by a barrier are
937“releasing” operations. (It would be wise to install the spin lock example
938firmly in mind, as the names are not otherwise intuitive.)</p>
939
940<p>Rewriting the spin lock example with this in mind:</p>
941
942<pre>do {
943 success = atomic_<strong>acquire</strong>_cas(&lock, 0, 1)
944} while (!success)
945
946<em>critical-section</em>
947
948atomic_<strong>release</strong>_store(&lock, 0)</pre>
949
950<p>This is a little more succinct and easier to read, but the real motivation
951for doing this lies in a couple of optimizations we can now perform.</p>
952
953<p>First, consider <code>atomic_release_store</code>. We need to ensure that
954the store of zero to the lock word is observed after any loads or stores in the
955critical section above it. In other words, we need a load/store and store/store
956barrier. In an earlier section we learned that these aren’t necessary on x86
957SMP -- only store/load barriers are required. The implementation of
958<code>atomic_release_store</code> on x86 is therefore just a compiler reorder
959barrier followed by a simple store. No CPU barrier is required.</p>
960
961<p>The second optimization mostly applies to the compiler (although some CPUs,
962such as the Itanium, can take advantage of it as well). The basic principle is
963that code can move across acquire and release barriers, but only in one
964direction.</p>
965
966<p>Suppose we have a mix of locally-visible and globally-visible memory
967accesses, with some miscellaneous computation as well:</p>
968
969<pre>local1 = arg1 / 41
970local2 = threadStruct->field2
971threadStruct->field3 = local2
972
973do {
974 success = atomic_acquire_cas(&lock, 0, 1)
975} while (!success)
976
977local5 = globalStruct->field5
978globalStruct->field6 = local5
979
980atomic_release_store(&lock, 0)</pre>
981
982<p>Here we see two completely independent sets of operations. The first set
983operates on a thread-local data structure, so we’re not concerned about clashes
984with other threads. The second set operates on a global data structure, which
985must be protected with a lock.</p>
986
987<p>A full compiler reorder barrier in the atomic ops will ensure that the
988program order matches the source code order at the lock boundaries. However,
989allowing the compiler to interleave instructions can improve performance. Loads
990from memory can be slow, but the CPU can continue to execute instructions that
991don’t require the result of that load while waiting for it to complete. The
992code might execute more quickly if it were written like this instead:</p>
993
994<pre>do {
995 success = atomic_acquire_cas(&lock, 0, 1)
996} while (!success)
997
998local2 = threadStruct->field2
999local5 = globalStruct->field5
1000local1 = arg1 / 41
1001threadStruct->field3 = local2
1002globalStruct->field6 = local5
1003
1004atomic_release_store(&lock, 0)</pre>
1005
1006<p>We issue both loads, do some unrelated computation, and then execute the
1007instructions that make use of the loads. If the integer division takes less
1008time than one of the loads, we essentially get it for free, since it happens
1009during a period where the CPU would have stalled waiting for a load to
1010complete.</p>
1011
1012<p>Note that <strong>all</strong> of the operations are now happening inside the
1013critical section. Since none of the “threadStruct” operations are visible
1014outside the current thread, nothing else can see them until we’re finished here,
1015so it doesn’t matter exactly when they happen.</p>
1016
1017<p>In general, it is always safe to move operations <strong>into</strong> a
1018critical section, but never safe to move operations <strong>out of</strong> a
1019critical section. Put another way, you can migrate code “downward” across an
1020acquire barrier, and “upward” across a release barrier. If the atomic ops used
1021a full barrier, this sort of migration would not be possible.</p>
1022
1023<p>Returning to an earlier point, we can state that on x86 all loads are
1024acquiring loads, and all stores are releasing stores. As a result:</p>
1025
1026<ul>
1027<li>Loads may not be reordered with respect to each other. You can’t take a
1028load and move it “upward” across another load’s acquire barrier.</li>
1029<li>Stores may not be reordered with respect to each other, because you can’t
1030move a store “downward” across another store’s release barrier.</li>
1031<li>A load followed by a store can’t be reordered, because neither instruction
1032will tolerate it.</li>
1033<li>A store followed by a load <strong>can</strong> be reordered, because each
1034instruction can move across the other in that direction.</li>
1035</ul>
1036
1037<p>Hence, you only need store/load barriers on x86 SMP.</p>
1038
1039<p>Labeling atomic operations with “acquire” or “release” describes not only
1040whether the barrier is executed before or after the atomic operation, but also
1041how the compiler is allowed to reorder code.</p>
1042
1043<h2 id="practice">Practice</h2>
1044
1045<p>Debugging memory consistency problems can be very difficult. If a missing
1046memory barrier causes some code to read stale data, you may not be able to
1047figure out why by examining memory dumps with a debugger. By the time you can
1048issue a debugger query, the CPU cores will have all observed the full set of
1049accesses, and the contents of memory and the CPU registers will appear to be in
1050an “impossible” state.</p>
1051
1052<h3 id="c_dont">What not to do in C</h3>
1053
1054<p>Here we present some examples of incorrect code, along with simple ways to
1055fix them. Before we do that, we need to discuss the use of a basic language
1056feature.</p>
1057
1058<h4 id="volatile">C/C+++ and "volatile"</h4>
1059
1060<p>When writing single-threaded code, declaring a variable “volatile” can be
1061very useful. The compiler will not omit or reorder accesses to volatile
1062locations. Combine that with the sequential consistency provided by the
1063hardware, and you’re guaranteed that the loads and stores will appear to happen
1064in the expected order.</p>
1065
1066<p>However, accesses to volatile storage may be reordered with non-volatile
1067accesses, so you have to be careful in multi-threaded uniprocessor environments
1068(explicit compiler reorder barriers may be required). There are no atomicity
1069guarantees, and no memory barrier provisions, so “volatile” doesn’t help you at
1070all in multi-threaded SMP environments. The C and C++ language standards are
1071being updated to address this with built-in atomic operations.</p>
1072
1073<p>If you think you need to declare something “volatile”, that is a strong
1074indicator that you should be using one of the atomic operations instead.</p>
1075
1076<h4 id="examplesc">Examples</h4>
1077
1078<p>In most cases you’d be better off with a synchronization primitive (like a
1079pthread mutex) rather than an atomic operation, but we will employ the latter to
1080illustrate how they would be used in a practical situation.</p>
1081
1082<p>For the sake of brevity we’re ignoring the effects of compiler optimizations
1083here &mdash; some of this code is broken even on uniprocessors &mdash; so for
1084all of these examples you must assume that the compiler generates
1085straightforward code (for example, compiled with gcc -O0). The fixes presented here do
1086solve both compiler-reordering and memory-access-ordering issues, but we’re only
1087going to discuss the latter.</p>
1088
1089<pre>MyThing* gGlobalThing = NULL;
1090
1091void initGlobalThing() // runs in thread 1
1092{
1093 MyStruct* thing = malloc(sizeof(*thing));
1094 memset(thing, 0, sizeof(*thing));
1095 thing->x = 5;
1096 thing->y = 10;
1097 /* initialization complete, publish */
1098 gGlobalThing = thing;
1099}
1100
1101void useGlobalThing() // runs in thread 2
1102{
1103 if (gGlobalThing != NULL) {
1104 int i = gGlobalThing->x; // could be 5, 0, or uninitialized data
1105 ...
1106 }
1107}</pre>
1108
1109<p>The idea here is that we allocate a structure, initialize its fields, and at
1110the very end we “publish” it by storing it in a global variable. At that point,
1111any other thread can see it, but that’s fine since it’s fully initialized,
1112right? At least, it would be on x86 SMP or a uniprocessor (again, making the
1113erroneous assumption that the compiler outputs code exactly as we have it in the
1114source).</p>
1115
1116<p>Without a memory barrier, the store to <code>gGlobalThing</code> could be observed before
1117the fields are initialized on ARM. Another thread reading from <code>thing->x</code> could
1118see 5, 0, or even uninitialized data.</p>
1119
1120<p>This can be fixed by changing the last assignment to:</p>
1121
1122<pre> atomic_release_store(&gGlobalThing, thing);</pre>
1123
1124<p>That ensures that all other threads will observe the writes in the proper
1125order, but what about reads? In this case we should be okay on ARM, because the
1126address dependency rules will ensure that any loads from an offset of
1127<code>gGlobalThing</code> are observed after the load of
1128<code>gGlobalThing</code>. However, it’s unwise to rely on architectural
1129details, since it means your code will be very subtly unportable. The complete
1130fix also requires a barrier after the load:</p>
1131
1132<pre> MyThing* thing = atomic_acquire_load(&gGlobalThing);
1133 int i = thing->x;</pre>
1134
1135<p>Now we know the ordering will be correct. This may seem like an awkward way
1136to write code, and it is, but that’s the price you pay for accessing data
1137structures from multiple threads without using locks. Besides, address
1138dependencies won’t always save us:</p>
1139
1140<pre>MyThing gGlobalThing;
1141
1142void initGlobalThing() // runs in thread 1
1143{
1144 gGlobalThing.x = 5;
1145 gGlobalThing.y = 10;
1146 /* initialization complete */
1147 gGlobalThing.initialized = true;
1148}
1149
1150void useGlobalThing() // runs in thread 2
1151{
1152 if (gGlobalThing.initialized) {
1153 int i = gGlobalThing.x; // could be 5 or 0
1154 }
1155}</pre>
1156
1157<p>Because there is no relationship between the <code>initialized</code> field and the
1158others, the reads and writes can be observed out of order. (Note global data is
1159initialized to zero by the OS, so it shouldn’t be possible to read “random”
1160uninitialized data.)</p>
1161
1162<p>We need to replace the store with:</p>
1163<pre> atomic_release_store(&gGlobalThing.initialized, true);</pre>
1164
1165<p>and replace the load with:</p>
1166<pre> int initialized = atomic_acquire_load(&gGlobalThing.initialized);</pre>
1167
1168<p>Another example of the same problem occurs when implementing
1169reference-counted data structures. The reference count itself will be
1170consistent so long as atomic increment and decrement operations are used, but
1171you can still run into trouble at the edges, for example:</p>
1172
1173<pre>void RefCounted::release()
1174{
1175 int oldCount = atomic_dec(&mRefCount);
1176 if (oldCount == 1) { // was decremented to zero
1177 recycleStorage();
1178 }
1179}
1180
1181void useSharedThing(RefCountedThing sharedThing)
1182{
1183 int localVar = sharedThing->x;
1184 sharedThing->release();
1185 sharedThing = NULL; // can’t use this pointer any more
1186 doStuff(localVar); // value of localVar might be wrong
1187}</pre>
1188
1189<p>The <code>release()</code> call decrements the reference count using a
1190barrier-free atomic decrement operation. Because this is an atomic RMW
1191operation, we know that it will work correctly. If the reference count goes to
1192zero, we recycle the storage.</p>
1193
1194<p>The <code>useSharedThing()</code> function extracts what it needs from
1195<code>sharedThing</code> and then releases its copy. However, because we didn’t
1196use a memory barrier, and atomic and non-atomic operations can be reordered,
1197it’s possible for other threads to observe the read of
1198<code>sharedThing->x</code> <strong>after</strong> they observe the recycle
1199operation. It’s therefore possible for <code>localVar</code> to hold a value
1200from "recycled" memory, for example a new object created in the same
1201location by another thread after <code>release()</code> is called.</p>
1202
1203<p>This can be fixed by replacing the call to <code>atomic_dec()</code> with
1204<code>atomic_release_dec()</code>. The barrier ensures that the reads from
1205<code>sharedThing</code> are observed before we recycle the object.</p>
1206
1207<div style="padding:.5em 2em;">
1208<div style="border-left:4px solid #ccc;padding:0 1em;font-style:italic;">
1209<p>In most cases the above won’t actually fail, because the “recycle” function
1210is likely guarded by functions that themselves employ barriers (libc heap
1211<code>free()</code>/<code>delete()</code>, or an object pool guarded by a
1212mutex). If the recycle function used a lock-free algorithm implemented without
1213barriers, however, the above code could fail on ARM SMP.</p>
1214</div>
1215</div>
1216
1217<h3 id="j_dont">What not to do in Java</h3>
1218
1219<p>We haven’t discussed some relevant Java language features, so we’ll take a
1220quick look at those first.</p>
1221
1222<h4 id="sync_volatile">Java's "synchronized" and "volatile" keywords</h4>
1223
1224<p>The “synchronized” keyword provides the Java language’s in-built locking
1225mechanism. Every object has an associated “monitor” that can be used to provide
1226mutually exclusive access.</p>
1227
1228<p>The implementation of the “synchronized” block has the same basic structure
1229as the spin lock example: it begins with an acquiring CAS, and ends with a
1230releasing store. This means that compilers and code optimizers are free to
1231migrate code into a “synchronized” block. One practical consequence: you must
1232<strong>not</strong> conclude that code inside a synchronized block happens
1233after the stuff above it or before the stuff below it in a function. Going
1234further, if a method has two synchronized blocks that lock the same object, and
1235there are no operations in the intervening code that are observable by another
1236thread, the compiler may perform “lock coarsening” and combine them into a
1237single block.</p>
1238
1239<p>The other relevant keyword is “volatile”. As defined in the specification
1240for Java 1.4 and earlier, a volatile declaration was about as weak as its C
1241counterpart. The spec for Java 1.5 was updated to provide stronger guarantees,
1242almost to the level of monitor synchronization.</p>
1243
1244<p>The effects of volatile accesses can be illustrated with an example. If
1245thread 1 writes to a volatile field, and thread 2 subsequently reads from that
1246same field, then thread 2 is guaranteed to see that write and all writes
1247previously made by thread 1. More generally, the writes made by
1248<strong>any</strong> thread up to the point where it writes the field will be
1249visible to thead 2 when it does the read. In effect, writing to a volatile is
1250like a monitor release, and reading from a volatile is like a monitor
1251acquire.</p>
1252
1253<p>Non-volatile accesses may be reorded with respect to volatile accesses in the
1254usual ways, for example the compiler could move a non-volatile load or store “above” a
1255volatile store, but couldn’t move it “below”. Volatile accesses may not be
1256reordered with respect to each other. The VM takes care of issuing the
1257appropriate memory barriers.</p>
1258
1259<p>It should be mentioned that, while loads and stores of object references and
1260most primitive types are atomic, <code>long</code> and <code>double</code>
1261fields are not accessed atomically unless they are marked as volatile.
1262Multi-threaded updates to non-volatile 64-bit fields are problematic even on
1263uniprocessors.</p>
1264
1265<h4 id="examplesj">Examples</h4>
1266
1267<p>Here’s a simple, incorrect implementation of a monotonic counter: <span
1268style="font-size:.9em;color:#777">(<em><a href="#more" style="color:#777">Java
1269theory and practice: Managing volatility</a></em>)</span>.</p>
1270
1271<pre>class Counter {
1272 private int mValue;
1273
1274 public int get() {
1275 return mValue;
1276 }
1277 public void incr() {
1278 mValue++;
1279 }
1280}</pre>
1281
1282<p>Assume <code>get()</code> and <code>incr()</code> are called from multiple
1283threads, and we want to be sure that every thread sees the current count when
1284<code>get()</code> is called. The most glaring problem is that
1285<code>mValue++</code> is actually three operations:</p>
1286
1287<ol>
1288<li><code>reg = mValue</code></li>
1289<li><code>reg = reg + 1</code></li>
1290<li><code>mValue = reg</code></li>
1291</ol>
1292
1293<p>If two threads execute in <code>incr()</code> simultaneously, one of the
1294updates could be lost. To make the increment atomic, we need to declare
1295<code>incr()</code> “synchronized”. With this change, the code will run
1296correctly in multi-threaded uniprocessor environments.</p>
1297
1298<p>It’s still broken on SMP, however. Different threads might see different
1299results from <code>get()</code>, because we’re reading the value with an ordinary load. We
1300can correct the problem by declaring <code>get()</code> to be synchronized.
1301With this change, the code is obviously correct.</p>
1302
1303<p>Unfortunately, we’ve introduced the possibility of lock contention, which
1304could hamper performance. Instead of declaring <code>get()</code> to be
1305synchronized, we could declare <code>mValue</code> with “volatile”. (Note
1306<code>incr()</code> must still use <code>synchronize</code>.) Now we know that
1307the volatile write to <code>mValue</code> will be visible to any subsequent volatile read of
1308<code>mValue</code>. <code>incr()</code> will be slightly slower, but
1309<code>get()</code> will be faster, so even in the absence of contention this is
1310a win if reads outnumber writes. (See also {@link
1311java.util.concurrent.atomic.AtomicInteger}.)</p>
1312
1313<p>Here’s another example, similar in form to the earlier C examples:</p>
1314
1315<pre>class MyGoodies {
1316 public int x, y;
1317}
1318class MyClass {
1319 static MyGoodies sGoodies;
1320
1321 void initGoodies() { // runs in thread 1
1322 MyGoodies goods = new MyGoodies();
1323 goods.x = 5;
1324 goods.y = 10;
1325 sGoodies = goods;
1326 }
1327
1328 void useGoodies() { // runs in thread 2
1329 if (sGoodies != null) {
1330 int i = sGoodies.x; // could be 5 or 0
1331 ....
1332 }
1333 }
1334}</pre>
1335
1336<p>This has the same problem as the C code, namely that the assignment
1337<code>sGoodies = goods</code> might be observed before the initialization of the
1338fields in <code>goods</code>. If you declare <code>sGoodies</code> with the
1339volatile keyword, you can think about the loads as if they were
1340<code>atomic_acquire_load()</code> calls, and the stores as if they were
1341<code>atomic_release_store()</code> calls.</p>
1342
1343<p>(Note that only the <code>sGoodies</code> reference itself is volatile. The
1344accesses to the fields inside it are not. The statement <code>z =
1345sGoodies.x</code> will perform a volatile load of <code>MyClass.sGoodies</code>
1346followed by a non-volatile load of <code>sGoodies.x</code>. If you make a local
1347reference <code>MyGoodies localGoods = sGoodies</code>, <code>z =
1348localGoods.x</code> will not perform any volatile loads.)</p>
1349
1350<p>A more common idiom in Java programming is the infamous “double-checked
1351locking”:</p>
1352
1353<pre>class MyClass {
1354 private Helper helper = null;
1355
1356 public Helper getHelper() {
1357 if (helper == null) {
1358 synchronized (this) {
1359 if (helper == null) {
1360 helper = new Helper();
1361 }
1362 }
1363 }
1364 return helper;
1365 }
1366}</pre>
1367
1368<p>The idea is that we want to have a single instance of a <code>Helper</code>
1369object associated with an instance of <code>MyClass</code>. We must only create
1370it once, so we create and return it through a dedicated <code>getHelper()</code>
1371function. To avoid a race in which two threads create the instance, we need to
1372synchronize the object creation. However, we don’t want to pay the overhead for
1373the “synchronized” block on every call, so we only do that part if
1374<code>helper</code> is currently null.</p>
1375
1376<p>This doesn’t work correctly on uniprocessor systems, unless you’re using a
1377traditional Java source compiler and an interpreter-only VM. Once you add fancy
1378code optimizers and JIT compilers it breaks down. See the “‘Double Checked
1379Locking is Broken’ Declaration” link in the appendix for more details, or Item
138071 (“Use lazy initialization judiciously”) in Josh Bloch’s <em>Effective Java,
13812nd Edition.</em>.</p>
1382
1383<p>Running this on an SMP system introduces an additional way to fail. Consider
1384the same code rewritten slightly, as if it were compiled into a C-like language
1385(I’ve added a couple of integer fields to represent <code>Helper’s</code>
1386constructor activity):</p>
1387
1388<pre>if (helper == null) {
1389 // acquire monitor using spinlock
1390 while (atomic_acquire_cas(&this.lock, 0, 1) != success)
1391 ;
1392 if (helper == null) {
1393 newHelper = malloc(sizeof(Helper));
1394 newHelper->x = 5;
1395 newHelper->y = 10;
1396 helper = newHelper;
1397 }
1398 atomic_release_store(&this.lock, 0);
1399}</pre>
1400
1401<p>Now the problem should be obvious: the store to <code>helper</code> is
1402happening before the memory barrier, which means another thread could observe
1403the non-null value of <code>helper</code> before the stores to the
1404<code>x</code>/<code>y</code> fields.</p>
1405
1406<p>You could try to ensure that the store to <code>helper</code> happens after
1407the <code>atomic_release_store()</code> on <code>this.lock</code> by rearranging
1408the code, but that won’t help, because it’s okay to migrate code upward &mdash;
1409the compiler could move the assignment back above the
1410<code>atomic_release_store()</code> to its original position.</p>
1411
1412<p>There are two ways to fix this:</p>
1413<ol>
1414<li>Do the simple thing and delete the outer check. This ensures that we never
1415examine the value of <code>helper</code> outside a synchronized block.</li>
1416<li>Declare <code>helper</code> volatile. With this one small change, the code
1417in Example J-3 will work correctly on Java 1.5 and later. (You may want to take
1418a minute to convince yourself that this is true.)</li>
1419</ol>
1420
1421<p>This next example illustrates two important issues when using volatile:</p>
1422
1423<pre>class MyClass {
1424 int data1, data2;
1425 volatile int vol1, vol2;
1426
1427 void setValues() { // runs in thread 1
1428 data1 = 1;
1429 vol1 = 2;
1430 data2 = 3;
1431 }
1432
1433 void useValues1() { // runs in thread 2
1434 if (vol1 == 2) {
1435 int l1 = data1; // okay
1436 int l2 = data2; // wrong
1437 }
1438 }
1439 void useValues2() { // runs in thread 2
1440 int dummy = vol2;
1441 int l1 = data1; // wrong
1442 int l2 = data2; // wrong
1443 }</pre>
1444
1445<p>Looking at <code>useValues1()</code>, if thread 2 hasn’t yet observed the
1446update to <code>vol1</code>, then it can’t know if <code>data1</code> or
1447<code>data2</code> has been set yet. Once it sees the update to
1448<code>vol1</code>, it knows that the change to <code>data1</code> is also
1449visible, because that was made before <code>vol1</code> was changed. However,
1450it can’t make any assumptions about <code>data2</code>, because that store was
1451performed after the volatile store.</p>
1452
1453<P>The code in <code>useValues2()</code> uses a second volatile field,
1454<code>vol2</code>, in an attempt to force the VM to generate a memory barrier.
1455This doesn’t generally work. To establish a proper “happens-before”
1456relationship, both threads need to be interacting with the same volatile field.
1457You’d have to know that <code>vol2</code> was set after <code>data1/data2</code>
1458in thread 1. (The fact that this doesn’t work is probably obvious from looking
1459at the code; the caution here is against trying to cleverly “cause” a memory
1460barrier instead of creating an ordered series of accesses.)</p>
1461
1462<h3 id="bestpractice">What to do</h3>
1463
1464<h4 id="advice">General advice</h4>
1465
1466<p>In C/C++, use the <code>pthread</code> operations, like mutexes and
1467semaphores. These include the proper memory barriers, providing correct and
1468efficient behavior on all Android platform versions. Be sure to use them
1469correctly, for example be wary of signaling a condition variable without holding the
1470corresponding mutex.</p>
1471
1472<p>It's best to avoid using atomic functions directly. Locking and
1473unlocking a pthread mutex require a single atomic operation each if there’s no
1474contention, so you’re not going to save much by replacing mutex calls with
1475atomic ops. If you need a lock-free design, you must fully understand the
1476concepts in this entire document before you begin (or, better yet, find an
1477existing code library that is known to be correct on SMP ARM).</p>
1478
1479<p>Be extremely circumspect with "volatile” in C/C++. It often indicates a
1480concurrency problem waiting to happen.</p>
1481
1482<p>In Java, the best answer is usually to use an appropriate utility class from
1483the {@link java.util.concurrent} package. The code is well written and well
1484tested on SMP.</p>
1485
1486<p>Perhaps the safest thing you can do is make your class immutable. Objects
1487from classes like String and Integer hold data that cannot be changed once the
1488class is created, avoiding all synchronization issues. The book <em>Effective
1489Java, 2nd Ed.</em> has specific instructions in “Item 15: Minimize Mutability”. Note in
1490particular the importance of declaring fields “final" <span
1491style="font-size:.9em;color:#777">(<a href="#more" style="color:#777">Bloch</a>)</span>.</p>
1492
1493<p>If neither of these options is viable, the Java “synchronized” statement
1494should be used to guard any field that can be accessed by more than one thread.
1495If mutexes won’t work for your situation, you should declare shared fields
1496“volatile”, but you must take great care to understand the interactions between
1497threads. The volatile declaration won’t save you from common concurrent
1498programming mistakes, but it will help you avoid the mysterious failures
1499associated with optimizing compilers and SMP mishaps.</p>
1500
1501<p>The Java Memory Model guarantees that assignments to final fields are visible
1502to all threads once the constructor has finished &mdash; this is what ensures
1503proper synchronization of fields in immutable classes. This guarantee does not
1504hold if a partially-constructed object is allowed to become visible to other
1505threads. It is necessary to follow safe construction practices.<span
1506style="font-size:.9em;color:#777">(<a href="#more" style="color:#777">Safe
1507Construction Techniques in Java</a>)</span>.</p>
1508
1509<h4 id="sync_guarantees">Synchronization primitive guarantees</h4>
1510
1511<p>The pthread library and VM make a couple of useful guarantees: all accesses
1512previously performed by a thread that creates a new thread are observable by
1513that new thread as soon as it starts, and all accesses performed by a thread
1514that is exiting are observable when a <code>join()</code> on that thread
1515returns. This means you don’t need any additional synchronization when
1516preparing data for a new thread or examining the results of a joined thread.</p>
1517
1518<p>Whether or not these guarantees apply to interactions with pooled threads
1519depends on the thread pool implementation.</p>
1520
1521<p>In C/C++, the pthread library guarantees that any accesses made by a thread
1522before it unlocks a mutex will be observable by another thread after it locks
1523that same mutex. It also guarantees that any accesses made before calling
1524<code>signal()</code> or <code>broadcast()</code> on a condition variable will
1525be observable by the woken thread.</p>
1526
1527<p>Java language threads and monitors make similar guarantees for the comparable
1528operations.</p>
1529
1530<h4 id="ccpp_changes">Upcoming changes to C/C++</h4>
1531
1532<p>The C and C++ language standards are evolving to include a sophisticated
1533collection of atomic operations. A full matrix of calls for common data types
1534is defined, with selectable memory barrier semantics (choose from relaxed,
1535consume, acquire, release, acq_rel, seq_cst).</p>
1536
1537<p>See the <a href="#more">Further Reading</a> section for pointers to the
1538specifications.</p>
1539
1540
1541<h2 id="closing_notes">Closing Notes</h2>
1542
1543<p>While this document does more than merely scratch the surface, it doesn’t
1544manage more than a shallow gouge. This is a very broad and deep topic. Some
1545areas for further exploration:</p>
1546
1547<ul>
1548<li>Learn the definitions of <em>happens-before</em>,
1549<em>synchronizes-with</em>, and other essential concepts from the Java Memory
1550Model. (It’s hard to understand what “volatile” really means without getting
1551into this.)</li>
1552<li>Explore what compilers are and aren’t allowed to do when reordering code.
1553(The JSR-133 spec has some great examples of legal transformations that lead to
1554unexpected results.)</li>
1555<li>Find out how to write immutable classes in Java and C++. (There’s more to
1556it than just “don’t change anything after construction”.)</li>
1557<li>Internalize the recommendations in the Concurrency section of <em>Effective
1558Java, 2nd Edition.</em> (For example, you should avoid calling methods that are
1559meant to be overridden while inside a synchronized block.)</li>
1560<li>Understand what sorts of barriers you can use on x86 and ARM. (And other
1561CPUs for that matter, for example Itanium’s acquire/release instruction
1562modifiers.)</li>
1563<li>Read through the {@link java.util.concurrent} and {@link
1564java.util.concurrent.atomic} APIs to see what's available. Consider using
1565concurrency annotations like <code>@ThreadSafe</code> and
1566<code>@GuardedBy</code> (from net.jcip.annotations).</li>
1567</ul>
1568
1569<p>The <a href="#more">Further Reading</a> section in the appendix has links to
1570documents and web sites that will better illuminate these topics.</p>
1571
1572<h2 id="appendix">Appendix</h2>
1573
1574<h3 id="smp_failure_example">SMP failure example</h3>
1575
1576<p>This document describes a lot of “weird” things that can, in theory, happen.
1577If you’re not convinced that these issues are real, a practical example may be
1578useful.</p>
1579
1580<p>Bill Pugh’s Java memory model <a
1581href="http://www.cs.umd.edu/~pugh/java/memoryModel/">web site</a> has a few
1582test programs on it. One interesting test is ReadAfterWrite.java, which does
1583the following:</p>
1584
1585<table>
1586<tr>
1587<th>Thread 1</th>
1588<th>Thread 2</th>
1589</tr>
1590<tr>
1591<td><code>for (int i = 0; i < ITERATIONS; i++) {<br />
1592&nbsp;&nbsp;&nbsp;&nbsp;a = i;<br />
1593&nbsp;&nbsp;&nbsp;&nbsp;BB[i] = b;<br />
1594}</code></td>
1595<td><code>for (int i = 0; i < ITERATIONS; i++) {<br />
1596&nbsp;&nbsp;&nbsp;&nbsp;b = i;<br />
1597&nbsp;&nbsp;&nbsp;&nbsp;AA[i] = a;<br />
1598}</code></td>
1599</tr>
1600</table>
1601
1602<p>Where <code>a</code> and <code>b</code> are declared as volatile
1603<code>int</code> fields, and <code>AA</code> and <code>BB</code> are ordinary
1604integer arrays.
1605
1606<p>This is trying to determine if the VM ensures that, after a value is written
1607to a volatile, the next read from that volatile sees the new value. The test
1608code executes these loops a million or so times, and then runs through afterward
1609and searches the results for inconsistencies.</p>
1610
1611<p>At the end of execution,<code>AA</code> and <code>BB</code> will be full of
1612gradually-increasing integers. The threads will not run side-by-side in a
1613predictable way, but we can assert a relationship between the array contents.
1614For example, consider this execution fragment:</p>
1615
1616<table>
1617<tr>
1618<th>Thread 1</th>
1619<th>Thread 2</th>
1620</tr>
1621<tr>
1622<td><code>(initially a == 1534)<br />
1623a = 1535<br />
1624BB[1535] = 165<br />
1625a = 1536<br />
1626BB[1536] = 165<br />
1627<br />
1628<br />
1629<br />
1630<br />
1631a = 1537<br />
1632BB[1537] = 167</code></td>
1633<td><code>(initially b == 165)
1634<br />
1635<br />
1636<br />
1637<br />
1638<br />
1639b = 166<br />
1640AA[166] = 1536<br />
1641b = 167<br />
1642AA[167] = 1536<br />
1643<br /></code></td>
1644</tr>
1645</table>
1646
1647<p>(This is written as if the threads were taking turns executing so that it’s
1648more obvious when results from one thread should be visible to the other, but in
1649practice that won’t be the case.)</p>
1650
1651<p>Look at the assignment of <code>AA[166]</code> in thread 2. We are capturing
1652the fact that, at the point where thread 2 was on iteration 166, it can see that
1653thread 1 was on iteration 1536. If we look one step in the future, at thread
16541’s iteration 1537, we expect to see that thread 1 saw that thread 2 was at
1655iteration 166 (or later). <code>BB[1537]</code> holds 167, so it appears things
1656are working.</p>
1657
1658<p>Now suppose we fail to observe a volatile write to <code>b</code>:</p>
1659
1660<table>
1661<tr>
1662<th>Thread 1</th>
1663<th>Thread 2</th>
1664</tr>
1665<tr>
1666<td><code>(initially a == 1534)<br />
1667a = 1535<br />
1668BB[1535] = 165<br />
1669a = 1536<br />
1670BB[1536] = 165<br />
1671<br />
1672<br />
1673<br />
1674<br />
1675a = 1537<br />
1676BB[1537] = 165 // stale b</code></td>
1677<td><code>(initially b == 165)<br />
1678<br />
1679<br />
1680<br />
1681<br />
1682b = 166<br />
1683AA[166] = 1536<br />
1684b = 167<br />
1685AA[167] = 1536</code></td>
1686</tr>
1687</table>
1688
1689<p>Now, <code>BB[1537]</code> holds 165, a smaller value than we expected, so we
1690know we have a problem. Put succinctly, for i=166, BB[AA[i]+1] < i. (This also
1691catches failures by thread 2 to observe writes to <code>a</code>, for example if we
1692miss an update and assign <code>AA[166] = 1535</code>, we will get
1693<code>BB[AA[166]+1] == 165</code>.)</p>
1694
1695<p>If you run the test program under Dalvik (Android 3.0 “Honeycomb” or later)
1696on an SMP ARM device, it will never fail. If you remove the word “volatile”
1697from the declarations of <code>a</code> and <code>b</code>, it will consistently
1698fail. The program is testing to see if the VM is providing sequentially
1699consistent ordering for accesses to <code>a</code> and <code>b</code>, so you
1700will only see correct behavior when the variables are volatile. (It will also
1701succeed if you run the code on a uniprocessor device, or run it while something
1702else is using enough CPU that the kernel doesn’t schedule the test threads on
1703separate cores.)</p>
1704
1705<p>If you run the modified test a few times you will note that it doesn’t fail
1706in the same place every time. The test fails consistently because it performs
1707the operations a million times, and it only needs to see out-of-order accesses
1708once. In practice, failures will be infrequent and difficult to locate. This
1709test program could very well succeed on a broken VM if things just happen to
1710work out.</p>
1711
1712<h3 id="sync_stores">Implementing synchronization stores</h3>
1713
1714<p><em>(This isn’t something most programmers will find themselves implementing,
1715but the discussion is illuminating.)</em></p>
1716
1717<p>Consider once again volatile accesses in Java. Earlier we made reference to
1718their similarities with acquiring loads and releasing stores, which works as a
1719starting point but doesn’t tell the full story.</p>
1720
1721<p>We start with a fragment of Dekker’s algorithm. Initially both
1722<code>flag1</code> and <code>flag2</code> are false:</p>
1723
1724<table>
1725<tr>
1726<th>Thread 1</th>
1727<th>Thread 2</th>
1728</tr>
1729<tr>
1730<td><code>flag1 = true<br />
1731if (flag2 == false)<br />
1732&nbsp;&nbsp;&nbsp;&nbsp;<em>critical-stuff</em></code></td>
1733<td><code>flag2 = true<br />
1734if (flag1 == false)<br />
1735&nbsp;&nbsp;&nbsp;&nbsp;<em>critical-stuff</em></code></td>
1736</tr>
1737</table
1738
1739<p><code>flag1</code> and <code>flag2</code> are declared as volatile boolean
1740fields. The rules for acquiring loads and releasing stores would allow the
1741accesses in each thread to be reordered, breaking the algorithm. Fortunately,
1742the JMM has a few things to say here. Informally:</p>
1743
1744<ul>
1745<li>A write to a volatile field <em>happens-before</em> every subsequent read of that
1746same field. (For this example, it means that if one thread updates a flag, and
1747later on the other thread reads that flag, the reader is guaranteed to see the
1748write.)</li>
1749<li>Every execution has a total order over all volatile field accesses. The
1750order is consistent with program order.</li>
1751</ul>
1752
1753<p>Taken together, these rules say that the volatile accesses in our example
1754must be observable in program order by all threads. Thus, we will never see
1755these threads executing the “critical-stuff” simultaneously.</p>
1756
1757<div style="padding:.5em 2em;">
1758<div style="border-left:4px solid #999;padding:0 1em;font-style:italic;">
1759<p>Another way to think about this is in terms of <em>data races</em>. A data race
1760occurs if two accesses to the same memory location by different threads are not
1761ordered, at least one of them stores to the memory location, and at least one of
1762them is not a synchronization action <span style="font-size:.9em;color:#777">(<a
1763href="#more" style="color:#777">Boehm and McKenney</a>)</span>. The memory model
1764declares that a program free of data races must behave as if executed by a
1765sequentially-consistent machine. Because both <code>flag1</code> and
1766<code>flag2</code> are volatile, and volatile accesses are considered
1767synchronization actions, there are no data races and this code must execute in a
1768sequentially consistent manner.</p>
1769</div>
1770</div>
1771
1772<p>As we saw in an earlier section, we need to insert a store/load barrier
1773between the two operations. The code executed in the VM for a volatile access
1774will look something like this:</p>
1775
1776<table>
1777<tr>
1778<th>volatile load</th>
1779<th>volatile store</th>
1780</tr>
1781<tr>
1782<td><code>reg = A<br />
1783<em>load/load + load/store barrier</em></code></td>
1784<td><code><em>store/store barrier</em><br />
1785A = reg<br />
1786<em>store/load barrier</em></code></td>
1787</tr>
1788</table>
1789
1790<p>The volatile load is just an acquiring load. The volatile store is similar
1791to a releasing store, but we’ve omitted load/store from the pre-store barrier,
1792and added a store/load barrier afterward.</p>
1793
1794<p>What we’re really trying to guarantee, though, is that (using thread 1 as an
1795example) the write to flag1 is observed before the read of flag2. We could
1796issue the store/load barrier before the volatile load instead and get the same
1797result, but because loads tend to outnumber stores it’s best to associate it
1798with the store.</p>
1799
1800<p>On some architectures, it’s possible to implement volatile stores with an
1801atomic operation and skip the explicit store/load barrier. On x86, for example,
1802atomics provide a full barrier. The ARM LL/SC operations don’t include a
1803barrier, so for ARM we must use explicit barriers.</p>
1804
1805<p>(Much of this is due to Doug Lea and his “JSR-133 Cookbook for Compiler
1806Writers” page.)</p>
1807
1808<h3 id="more">Further reading</h3>
1809
1810<p>Web pages and documents that provide greater depth or breadth. The more generally useful articles are nearer the top of the list.</p>
1811
1812<dl>
1813<dt>Shared Memory Consistency Models: A Tutorial</dt>
1814<dd>Written in 1995 by Adve & Gharachorloo, this is a good place to start if you want to dive more deeply into memory consistency models.
1815<br /><a href="http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-95-7.pdf">http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-95-7.pdf</a></dd>
1816
1817<dt>Memory Barriers</dt>
1818<dd>Nice little article summarizing the issues.
1819<br /><a href="http://en.wikipedia.org/wiki/Memory_barrier">http://en.wikipedia.org/wiki/Memory_barrier</a></dd>
1820
1821<dt>Threads Basics</dt>
1822<dd>An introduction to multi-threaded programming in C++ and Java, by Hans Boehm. Excellent discussion of data races and basic synchronization methods.
1823<br /><a href="http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/threadsintro.html">http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/threadsintro.html</a></dd>
1824
1825<dt>Java Concurrency In Practice</dt>
1826<dd>Published in 2006, this book covers a wide range of topics in great detail. Highly recommended for anyone writing multi-threaded code in Java.
1827<br /><a href="http://www.javaconcurrencyinpractice.com">http://www.javaconcurrencyinpractice.com</a></dd>
1828
1829<dt>JSR-133 (Java Memory Model) FAQ</dt>
1830<dd>A gentle introduction to the Java memory model, including an explanation of synchronization, volatile variables, and construction of final fields.
1831<br /><a href="http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html">http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html</a></dd>
1832
1833<dt>Overview of package java.util.concurrent</dt>
1834<dd>The documentation for the <code>java.util.concurrent</code> package. Near the bottom of the page is a section entitled “Memory Consistency Properties” that explains the guarantees made by the various classes.
1835<br />{@link java.util.concurrent java.util.concurrent} Package Summary</dd>
1836
1837<dt>Java Theory and Practice: Safe Construction Techniques in Java</dt>
1838<dd>This article examines in detail the perils of references escaping during object construction, and provides guidelines for thread-safe constructors.
1839<br /><a href="http://www.ibm.com/developerworks/java/library/j-jtp0618.html">http://www.ibm.com/developerworks/java/library/j-jtp0618.html</a></dd>
1840
1841<dt>Java Theory and Practice: Managing Volatility</dt>
1842<dd>A nice article describing what you can and can’t accomplish with volatile fields in Java.
1843<br /><a href="http://www.ibm.com/developerworks/java/library/j-jtp06197.html">http://www.ibm.com/developerworks/java/library/j-jtp06197.html</a></dd>
1844
1845<dt>The “Double-Checked Locking is Broken” Declaration</dt>
1846<dd>Bill Pugh’s detailed explanation of the various ways in which double-checked locking is broken. Includes C/C++ and Java.
1847<br /><a href="http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html">http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html</a></dd>
1848
1849<dt>[ARM] Barrier Litmus Tests and Cookbook</dt>
1850<dd>A discussion of ARM SMP issues, illuminated with short snippets of ARM code. If you found the examples in this document too un-specific, or want to read the formal description of the DMB instruction, read this. Also describes the instructions used for memory barriers on executable code (possibly useful if you’re generating code on the fly).
1851<br /><a href="http://infocenter.arm.com/help/topic/com.arm.doc.genc007826/Barrier_Litmus_Tests_and_Cookbook_A08.pdf">http://infocenter.arm.com/help/topic/com.arm.doc.genc007826/Barrier_Litmus_Tests_and_Cookbook_A08.pdf</a></dd>
1852
1853<dt>Linux Kernel Memory Barriers
1854<dd>Documentation for Linux kernel memory barriers. Includes some useful examples and ASCII art.
1855<br/><a href="http://www.kernel.org/doc/Documentation/memory-barriers.txt">http://www.kernel.org/doc/Documentation/memory-barriers.txt</a></dd>
1856
1857<dt>ISO/IEC JTC1 SC22 WG21 (C++ standards) 14882 (C++ programming language), chapter 29 (“Atomic operations library”)</dt>
1858<dd>Draft standard for C++ atomic operation features.
1859<br /><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3090.pdf">http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3090.pdf</a>
1860<br/ >(intro: <a href="http://www.hpl.hp.com/techreports/2008/HPL-2008-56.pdf">http://www.hpl.hp.com/techreports/2008/HPL-2008-56.pdf</a>)</dd>
1861
1862<dt>ISO/IEC JTC1 SC22 WG14 (C standards) 9899 (C programming language) chapter 7.16 (“Atomics &lt;stdatomic.h&gt;”)</dt>
1863<dd>Draft standard for ISO/IEC 9899-201x C atomic operation features. (See also n1484 for errata.)
1864<br /><a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1425.pdf">http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1425.pdf</a></dd>
1865
1866<dt>Dekker’s algorithm</dt>
1867<dd>The “first known correct solution to the mutual exclusion problem in concurrent programming”. The wikipedia article has the full algorithm, with a discussion about how it would need to be updated to work with modern optimizing compilers and SMP hardware.
1868<br /><a href="http://en.wikipedia.org/wiki/Dekker's_algorithm">http://en.wikipedia.org/wiki/Dekker's_algorithm</a></dd>
1869
1870<dt>Comments on ARM vs. Alpha and address dependencies</dt>
1871<dd>An e-mail on the arm-kernel mailing list from Catalin Marinas. Includes a nice summary of address and control dependencies.
1872<br /><a href="http://linux.derkeiler.com/Mailing-Lists/Kernel/2009-05/msg11811.html">http://linux.derkeiler.com/Mailing-Lists/Kernel/2009-05/msg11811.html</a></dd>
1873
1874<dt>What Every Programmer Should Know About Memory</dt>
1875<dd>A very long and detailed article about different types of memory, particularly CPU caches, by Ulrich Drepper.
1876<br /><a href="http://www.akkadia.org/drepper/cpumemory.pdf">http://www.akkadia.org/drepper/cpumemory.pdf</a></dd>
1877
1878<dt>Reasoning about the ARM weakly consistent memory model</dt>
1879<dd>This paper was written by Chong & Ishtiaq of ARM, Ltd. It attempts to describe the ARM SMP memory model in a rigorous but accessible fashion. The definition of “observability” used here comes from this paper.
1880<br /><a href="http://portal.acm.org/ft_gateway.cfm?id=1353528&type=pdf&coll=&dl=&CFID=96099715&CFTOKEN=57505711">http://portal.acm.org/ft_gateway.cfm?id=1353528&type=pdf&coll=&dl=&CFID=96099715&CFTOKEN=57505711</a></dd>
1881
1882<dt>The JSR-133 Cookbook for Compiler Writers</dt>
1883<dd>Doug Lea wrote this as a companion to the JSR-133 (Java Memory Model) documentation. It goes much deeper into the details than most people will need to worry about, but it provides good fodder for contemplation.
1884<br /><a href="http://g.oswego.edu/dl/jmm/cookbook.html">http://g.oswego.edu/dl/jmm/cookbook.html</a></dd>
1885
1886<dt>The Semantics of Power and ARM Multiprocessor Machine Code</dt>
1887<dd>If you prefer your explanations in rigorous mathematical form, this is a fine place to go next.
1888<br /><a href="http://www.cl.cam.ac.uk/~pes20/weakmemory/draft-ppc-arm.pdf">http://www.cl.cam.ac.uk/~pes20/weakmemory/draft-ppc-arm.pdf</a></dd>
1889</dl>