Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

C/C++

Use Critical Sections (Preferably Locks) to Eliminate Races


Automate Acquire/Release

The whole system has to play by the rules—meaning the rules you wrote into your program. In particular, acquire and release fencing rules have to apply at every point beyond the source code, because when your program does strange things, it doesn't matter whether it was your compiler that reordered your statements or your processor that reordered the instructions emitted by the compiler. At the processor level, the only way to avoid instruction reordering is to use acquire- and release-style fences that most processors support as explicit standalone instructions. But you don't want to be in the business of writing fences by hand in your source code. So what can be done to control reordering?

Make the compiler both obey the rules and emit the right processor fences for you in one fell swoop: Use abstractions that express critical sections; namely, locks and atomic objects. Consider our first example of lock-based code, and how a compiler might translate it to specific "load-acquire" and "store-release" instructions when compiling for an IA64 processor:


mut.lock();      
  // "acquire" mut => ld.acq mut.var
 ... read/write x ...
mut.unlock();
  // "release" mut => st.rel mut.var

But what about lock-free code? Similarly, for our other opening example of lock-free styles, we get:


while( !myTurn ) { }
  // "acquire" => ld.acq myTurn
 ... read/write x ...
myTurn = false;      
  // "release" => st.rel myTurn 

Both styles end up generating similar instructions because they express the same concept of a critical section. So avoid writing fences by hand; use these abstractions, and let the compiler write them for you.

Summary

Protect all mutable shared objects from races by putting code that accesses them into critical sections. The critical section is a fundamental concept that applies equally to all kinds of synchronization: Entering a critical section—taking a lock or reading from an atomic variable—is an acquire operation. Exiting a critical section—releasing a lock or writing to an atomic variable—is a release operation.

Next month, I look at practical examples of how, and how not, to use critical sections, including combining different styles.

Notes

[1] J. Manson, W. Pugh, and S. Adve. "JSR-133: Java Memory Model and Thread Specification" (Java Community Process, 2004).

[2] Note that I'm not specifying whether two consecutive critical sections could overlap, by allowing the "release" end of the first critical section to pass the "acquire" start of the second critical section. Some memory models allow this, whereas others have an additional requirement that acquire and release operations can't pass each other. This design choice doesn't affect the examples in this article.

[3] People regularly propose schemes that are more finegrained and try to let the programmer specify which objects are actually significant and must respect the fence. These have not become very popular, at least not yet, primarily because doing this adds great complexity to the programming model in return for insufficient actual performance benefit in most use cases.


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.