490 lines
47 KiB
HTML
490 lines
47 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||
<html>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
<title>Usage examples</title>
|
||
<link rel="stylesheet" href="../../../doc/src/boostbook.css" type="text/css">
|
||
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
|
||
<link rel="home" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset">
|
||
<link rel="up" href="../atomic.html" title="Chapter 6. Boost.Atomic">
|
||
<link rel="prev" href="interface.html" title="Programming interfaces">
|
||
<link rel="next" href="limitations.html" title="Limitations">
|
||
</head>
|
||
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
|
||
<table cellpadding="2" width="100%"><tr>
|
||
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../boost.png"></td>
|
||
<td align="center"><a href="../../../index.html">Home</a></td>
|
||
<td align="center"><a href="../../../libs/libraries.htm">Libraries</a></td>
|
||
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
|
||
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
|
||
<td align="center"><a href="../../../more/index.htm">More</a></td>
|
||
</tr></table>
|
||
<hr>
|
||
<div class="spirit-nav">
|
||
<a accesskey="p" href="interface.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../atomic.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="limitations.html"><img src="../../../doc/src/images/next.png" alt="Next"></a>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
|
||
<a name="atomic.usage_examples"></a><a class="link" href="usage_examples.html" title="Usage examples">Usage examples</a>
|
||
</h2></div></div></div>
|
||
<div class="toc"><dl class="toc">
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.example_reference_counters">Reference
|
||
counting</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.example_spinlock">Spinlock</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.singleton">Singleton with
|
||
double-checked locking pattern</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.example_ringbuffer">Wait-free
|
||
ring buffer</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.mp_queue">Lock-free multi-producer
|
||
queue</a></span></dt>
|
||
</dl></div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="boost_atomic.usage_examples.example_reference_counters"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.example_reference_counters" title="Reference counting">Reference
|
||
counting</a>
|
||
</h3></div></div></div>
|
||
<div class="toc"><dl class="toc">
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.example_reference_counters.implementation">Implementation</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.example_reference_counters.usage">Usage</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.example_reference_counters.discussion">Discussion</a></span></dt>
|
||
</dl></div>
|
||
<p>
|
||
The purpose of a <span class="emphasis"><em>reference counter</em></span> is to count the number
|
||
of pointers to an object. The object can be destroyed as soon as the reference
|
||
counter reaches zero.
|
||
</p>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.example_reference_counters.implementation"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.example_reference_counters.implementation" title="Implementation">Implementation</a>
|
||
</h4></div></div></div>
|
||
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">intrusive_ptr</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">atomic</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
|
||
<span class="keyword">class</span> <span class="identifier">X</span> <span class="special">{</span>
|
||
<span class="keyword">public</span><span class="special">:</span>
|
||
<span class="keyword">typedef</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">intrusive_ptr</span><span class="special"><</span><span class="identifier">X</span><span class="special">></span> <span class="identifier">pointer</span><span class="special">;</span>
|
||
<span class="identifier">X</span><span class="special">()</span> <span class="special">:</span> <span class="identifier">refcount_</span><span class="special">(</span><span class="number">0</span><span class="special">)</span> <span class="special">{}</span>
|
||
|
||
<span class="keyword">private</span><span class="special">:</span>
|
||
<span class="keyword">mutable</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">atomic</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="identifier">refcount_</span><span class="special">;</span>
|
||
<span class="keyword">friend</span> <span class="keyword">void</span> <span class="identifier">intrusive_ptr_add_ref</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">X</span> <span class="special">*</span> <span class="identifier">x</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">x</span><span class="special">-></span><span class="identifier">refcount_</span><span class="special">.</span><span class="identifier">fetch_add</span><span class="special">(</span><span class="number">1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_relaxed</span><span class="special">);</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">friend</span> <span class="keyword">void</span> <span class="identifier">intrusive_ptr_release</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">X</span> <span class="special">*</span> <span class="identifier">x</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">x</span><span class="special">-></span><span class="identifier">refcount_</span><span class="special">.</span><span class="identifier">fetch_sub</span><span class="special">(</span><span class="number">1</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_release</span><span class="special">)</span> <span class="special">==</span> <span class="number">1</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">atomic_thread_fence</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_acquire</span><span class="special">);</span>
|
||
<span class="keyword">delete</span> <span class="identifier">x</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="special">}</span>
|
||
<span class="special">};</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.example_reference_counters.usage"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.example_reference_counters.usage" title="Usage">Usage</a>
|
||
</h4></div></div></div>
|
||
<pre class="programlisting"><span class="identifier">X</span><span class="special">::</span><span class="identifier">pointer</span> <span class="identifier">x</span> <span class="special">=</span> <span class="keyword">new</span> <span class="identifier">X</span><span class="special">;</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.example_reference_counters.discussion"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.example_reference_counters.discussion" title="Discussion">Discussion</a>
|
||
</h4></div></div></div>
|
||
<p>
|
||
Increasing the reference counter can always be done with <code class="literal">memory_order_relaxed</code>:
|
||
New references to an object can only be formed from an existing reference,
|
||
and passing an existing reference from one thread to another must already
|
||
provide any required synchronization.
|
||
</p>
|
||
<p>
|
||
It is important to enforce any possible access to the object in one thread
|
||
(through an existing reference) to <span class="emphasis"><em>happen before</em></span> deleting
|
||
the object in a different thread. This is achieved by a "release"
|
||
operation after dropping a reference (any access to the object through
|
||
this reference must obviously happened before), and an "acquire"
|
||
operation before deleting the object.
|
||
</p>
|
||
<p>
|
||
It would be possible to use <code class="literal">memory_order_acq_rel</code> for
|
||
the <code class="literal">fetch_sub</code> operation, but this results in unneeded
|
||
"acquire" operations when the reference counter does not yet
|
||
reach zero and may impose a performance penalty.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="boost_atomic.usage_examples.example_spinlock"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.example_spinlock" title="Spinlock">Spinlock</a>
|
||
</h3></div></div></div>
|
||
<div class="toc"><dl class="toc">
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.example_spinlock.implementation">Implementation</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.example_spinlock.usage">Usage</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.example_spinlock.discussion">Discussion</a></span></dt>
|
||
</dl></div>
|
||
<p>
|
||
The purpose of a <span class="emphasis"><em>spin lock</em></span> is to prevent multiple threads
|
||
from concurrently accessing a shared data structure. In contrast to a mutex,
|
||
threads will busy-wait and waste CPU cycles instead of yielding the CPU to
|
||
another thread. <span class="emphasis"><em>Do not use spinlocks unless you are certain that
|
||
you understand the consequences.</em></span>
|
||
</p>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.example_spinlock.implementation"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.example_spinlock.implementation" title="Implementation">Implementation</a>
|
||
</h4></div></div></div>
|
||
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">atomic</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
|
||
<span class="keyword">class</span> <span class="identifier">spinlock</span> <span class="special">{</span>
|
||
<span class="keyword">private</span><span class="special">:</span>
|
||
<span class="keyword">typedef</span> <span class="keyword">enum</span> <span class="special">{</span><span class="identifier">Locked</span><span class="special">,</span> <span class="identifier">Unlocked</span><span class="special">}</span> <span class="identifier">LockState</span><span class="special">;</span>
|
||
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">atomic</span><span class="special"><</span><span class="identifier">LockState</span><span class="special">></span> <span class="identifier">state_</span><span class="special">;</span>
|
||
|
||
<span class="keyword">public</span><span class="special">:</span>
|
||
<span class="identifier">spinlock</span><span class="special">()</span> <span class="special">:</span> <span class="identifier">state_</span><span class="special">(</span><span class="identifier">Unlocked</span><span class="special">)</span> <span class="special">{}</span>
|
||
|
||
<span class="keyword">void</span> <span class="identifier">lock</span><span class="special">()</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">while</span> <span class="special">(</span><span class="identifier">state_</span><span class="special">.</span><span class="identifier">exchange</span><span class="special">(</span><span class="identifier">Locked</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_acquire</span><span class="special">)</span> <span class="special">==</span> <span class="identifier">Locked</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="comment">/* busy-wait */</span>
|
||
<span class="special">}</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">void</span> <span class="identifier">unlock</span><span class="special">()</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">state_</span><span class="special">.</span><span class="identifier">store</span><span class="special">(</span><span class="identifier">Unlocked</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_release</span><span class="special">);</span>
|
||
<span class="special">}</span>
|
||
<span class="special">};</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.example_spinlock.usage"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.example_spinlock.usage" title="Usage">Usage</a>
|
||
</h4></div></div></div>
|
||
<pre class="programlisting"><span class="identifier">spinlock</span> <span class="identifier">s</span><span class="special">;</span>
|
||
|
||
<span class="identifier">s</span><span class="special">.</span><span class="identifier">lock</span><span class="special">();</span>
|
||
<span class="comment">// access data structure here</span>
|
||
<span class="identifier">s</span><span class="special">.</span><span class="identifier">unlock</span><span class="special">();</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.example_spinlock.discussion"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.example_spinlock.discussion" title="Discussion">Discussion</a>
|
||
</h4></div></div></div>
|
||
<p>
|
||
The purpose of the spinlock is to make sure that one access to the shared
|
||
data structure always strictly "happens before" another. The
|
||
usage of acquire/release in lock/unlock is required and sufficient to guarantee
|
||
this ordering.
|
||
</p>
|
||
<p>
|
||
It would be correct to write the "lock" operation in the following
|
||
way:
|
||
</p>
|
||
<pre class="programlisting"><span class="identifier">lock</span><span class="special">()</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">while</span> <span class="special">(</span><span class="identifier">state_</span><span class="special">.</span><span class="identifier">exchange</span><span class="special">(</span><span class="identifier">Locked</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_relaxed</span><span class="special">)</span> <span class="special">==</span> <span class="identifier">Locked</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="comment">/* busy-wait */</span>
|
||
<span class="special">}</span>
|
||
<span class="identifier">atomic_thread_fence</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_acquire</span><span class="special">);</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
<p>
|
||
This "optimization" is however a) useless and b) may in fact
|
||
hurt: a) Since the thread will be busily spinning on a blocked spinlock,
|
||
it does not matter if it will waste the CPU cycles with just "exchange"
|
||
operations or with both useless "exchange" and "acquire"
|
||
operations. b) A tight "exchange" loop without any memory-synchronizing
|
||
instruction introduced through an "acquire" operation will on
|
||
some systems monopolize the memory subsystem and degrade the performance
|
||
of other system components.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="boost_atomic.usage_examples.singleton"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.singleton" title="Singleton with double-checked locking pattern">Singleton with
|
||
double-checked locking pattern</a>
|
||
</h3></div></div></div>
|
||
<div class="toc"><dl class="toc">
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.singleton.implementation">Implementation</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.singleton.usage">Usage</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.singleton.discussion">Discussion</a></span></dt>
|
||
</dl></div>
|
||
<p>
|
||
The purpose of the <span class="emphasis"><em>Singleton with double-checked locking pattern</em></span>
|
||
is to ensure that at most one instance of a particular object is created.
|
||
If one instance has been created already, access to the existing object should
|
||
be as light-weight as possible.
|
||
</p>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.singleton.implementation"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.singleton.implementation" title="Implementation">Implementation</a>
|
||
</h4></div></div></div>
|
||
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">atomic</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
<span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">thread</span><span class="special">/</span><span class="identifier">mutex</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
|
||
<span class="keyword">class</span> <span class="identifier">X</span> <span class="special">{</span>
|
||
<span class="keyword">public</span><span class="special">:</span>
|
||
<span class="keyword">static</span> <span class="identifier">X</span> <span class="special">*</span> <span class="identifier">instance</span><span class="special">()</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">X</span> <span class="special">*</span> <span class="identifier">tmp</span> <span class="special">=</span> <span class="identifier">instance_</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_consume</span><span class="special">);</span>
|
||
<span class="keyword">if</span> <span class="special">(!</span><span class="identifier">tmp</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">mutex</span><span class="special">::</span><span class="identifier">scoped_lock</span> <span class="identifier">guard</span><span class="special">(</span><span class="identifier">instantiation_mutex</span><span class="special">);</span>
|
||
<span class="identifier">tmp</span> <span class="special">=</span> <span class="identifier">instance_</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_consume</span><span class="special">);</span>
|
||
<span class="keyword">if</span> <span class="special">(!</span><span class="identifier">tmp</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="identifier">tmp</span> <span class="special">=</span> <span class="keyword">new</span> <span class="identifier">X</span><span class="special">;</span>
|
||
<span class="identifier">instance_</span><span class="special">.</span><span class="identifier">store</span><span class="special">(</span><span class="identifier">tmp</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_release</span><span class="special">);</span>
|
||
<span class="special">}</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">return</span> <span class="identifier">tmp</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">private</span><span class="special">:</span>
|
||
<span class="keyword">static</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">atomic</span><span class="special"><</span><span class="identifier">X</span> <span class="special">*></span> <span class="identifier">instance_</span><span class="special">;</span>
|
||
<span class="keyword">static</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">mutex</span> <span class="identifier">instantiation_mutex</span><span class="special">;</span>
|
||
<span class="special">};</span>
|
||
|
||
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">atomic</span><span class="special"><</span><span class="identifier">X</span> <span class="special">*></span> <span class="identifier">X</span><span class="special">::</span><span class="identifier">instance_</span><span class="special">(</span><span class="number">0</span><span class="special">);</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.singleton.usage"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.singleton.usage" title="Usage">Usage</a>
|
||
</h4></div></div></div>
|
||
<pre class="programlisting"><span class="identifier">X</span> <span class="special">*</span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">X</span><span class="special">::</span><span class="identifier">instance</span><span class="special">();</span>
|
||
<span class="comment">// dereference x</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.singleton.discussion"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.singleton.discussion" title="Discussion">Discussion</a>
|
||
</h4></div></div></div>
|
||
<p>
|
||
The mutex makes sure that only one instance of the object is ever created.
|
||
The <code class="literal">instance</code> method must make sure that any dereference
|
||
of the object strictly "happens after" creating the instance
|
||
in another thread. The use of <code class="literal">memory_order_release</code> after
|
||
creating and initializing the object and <code class="literal">memory_order_consume</code>
|
||
before dereferencing the object provides this guarantee.
|
||
</p>
|
||
<p>
|
||
It would be permissible to use <code class="literal">memory_order_acquire</code>
|
||
instead of <code class="literal">memory_order_consume</code>, but this provides a
|
||
stronger guarantee than is required since only operations depending on
|
||
the value of the pointer need to be ordered.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="boost_atomic.usage_examples.example_ringbuffer"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.example_ringbuffer" title="Wait-free ring buffer">Wait-free
|
||
ring buffer</a>
|
||
</h3></div></div></div>
|
||
<div class="toc"><dl class="toc">
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.example_ringbuffer.implementation">Implementation</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.example_ringbuffer.usage">Usage</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.example_ringbuffer.discussion">Discussion</a></span></dt>
|
||
</dl></div>
|
||
<p>
|
||
A <span class="emphasis"><em>wait-free ring buffer</em></span> provides a mechanism for relaying
|
||
objects from one single "producer" thread to one single "consumer"
|
||
thread without any locks. The operations on this data structure are "wait-free"
|
||
which means that each operation finishes within a constant number of steps.
|
||
This makes this data structure suitable for use in hard real-time systems
|
||
or for communication with interrupt/signal handlers.
|
||
</p>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.example_ringbuffer.implementation"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.example_ringbuffer.implementation" title="Implementation">Implementation</a>
|
||
</h4></div></div></div>
|
||
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">atomic</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">></span>
|
||
|
||
<span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">,</span> <span class="identifier">size_t</span> <span class="identifier">Size</span><span class="special">></span>
|
||
<span class="keyword">class</span> <span class="identifier">ringbuffer</span> <span class="special">{</span>
|
||
<span class="keyword">public</span><span class="special">:</span>
|
||
<span class="identifier">ringbuffer</span><span class="special">()</span> <span class="special">:</span> <span class="identifier">head_</span><span class="special">(</span><span class="number">0</span><span class="special">),</span> <span class="identifier">tail_</span><span class="special">(</span><span class="number">0</span><span class="special">)</span> <span class="special">{}</span>
|
||
|
||
<span class="keyword">bool</span> <span class="identifier">push</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">T</span> <span class="special">&</span> <span class="identifier">value</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">size_t</span> <span class="identifier">head</span> <span class="special">=</span> <span class="identifier">head_</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_relaxed</span><span class="special">);</span>
|
||
<span class="identifier">size_t</span> <span class="identifier">next_head</span> <span class="special">=</span> <span class="identifier">next</span><span class="special">(</span><span class="identifier">head</span><span class="special">);</span>
|
||
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">next_head</span> <span class="special">==</span> <span class="identifier">tail_</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_acquire</span><span class="special">))</span>
|
||
<span class="keyword">return</span> <span class="keyword">false</span><span class="special">;</span>
|
||
<span class="identifier">ring_</span><span class="special">[</span><span class="identifier">head</span><span class="special">]</span> <span class="special">=</span> <span class="identifier">value</span><span class="special">;</span>
|
||
<span class="identifier">head_</span><span class="special">.</span><span class="identifier">store</span><span class="special">(</span><span class="identifier">next_head</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_release</span><span class="special">);</span>
|
||
<span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">bool</span> <span class="identifier">pop</span><span class="special">(</span><span class="identifier">T</span> <span class="special">&</span> <span class="identifier">value</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">size_t</span> <span class="identifier">tail</span> <span class="special">=</span> <span class="identifier">tail_</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_relaxed</span><span class="special">);</span>
|
||
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">tail</span> <span class="special">==</span> <span class="identifier">head_</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_acquire</span><span class="special">))</span>
|
||
<span class="keyword">return</span> <span class="keyword">false</span><span class="special">;</span>
|
||
<span class="identifier">value</span> <span class="special">=</span> <span class="identifier">ring_</span><span class="special">[</span><span class="identifier">tail</span><span class="special">];</span>
|
||
<span class="identifier">tail_</span><span class="special">.</span><span class="identifier">store</span><span class="special">(</span><span class="identifier">next</span><span class="special">(</span><span class="identifier">tail</span><span class="special">),</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_release</span><span class="special">);</span>
|
||
<span class="keyword">return</span> <span class="keyword">true</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">private</span><span class="special">:</span>
|
||
<span class="identifier">size_t</span> <span class="identifier">next</span><span class="special">(</span><span class="identifier">size_t</span> <span class="identifier">current</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">return</span> <span class="special">(</span><span class="identifier">current</span> <span class="special">+</span> <span class="number">1</span><span class="special">)</span> <span class="special">%</span> <span class="identifier">Size</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="identifier">T</span> <span class="identifier">ring_</span><span class="special">[</span><span class="identifier">Size</span><span class="special">];</span>
|
||
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">atomic</span><span class="special"><</span><span class="identifier">size_t</span><span class="special">></span> <span class="identifier">head_</span><span class="special">,</span> <span class="identifier">tail_</span><span class="special">;</span>
|
||
<span class="special">};</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.example_ringbuffer.usage"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.example_ringbuffer.usage" title="Usage">Usage</a>
|
||
</h4></div></div></div>
|
||
<pre class="programlisting"><span class="identifier">ringbuffer</span><span class="special"><</span><span class="keyword">int</span><span class="special">,</span> <span class="number">32</span><span class="special">></span> <span class="identifier">r</span><span class="special">;</span>
|
||
|
||
<span class="comment">// try to insert an element</span>
|
||
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">r</span><span class="special">.</span><span class="identifier">push</span><span class="special">(</span><span class="number">42</span><span class="special">))</span> <span class="special">{</span> <span class="comment">/* succeeded */</span> <span class="special">}</span>
|
||
<span class="keyword">else</span> <span class="special">{</span> <span class="comment">/* buffer full */</span> <span class="special">}</span>
|
||
|
||
<span class="comment">// try to retrieve an element</span>
|
||
<span class="keyword">int</span> <span class="identifier">value</span><span class="special">;</span>
|
||
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">r</span><span class="special">.</span><span class="identifier">pop</span><span class="special">(</span><span class="identifier">value</span><span class="special">))</span> <span class="special">{</span> <span class="comment">/* succeeded */</span> <span class="special">}</span>
|
||
<span class="keyword">else</span> <span class="special">{</span> <span class="comment">/* buffer empty */</span> <span class="special">}</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.example_ringbuffer.discussion"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.example_ringbuffer.discussion" title="Discussion">Discussion</a>
|
||
</h4></div></div></div>
|
||
<p>
|
||
The implementation makes sure that the ring indices do not "lap-around"
|
||
each other to ensure that no elements are either lost or read twice.
|
||
</p>
|
||
<p>
|
||
Furthermore it must guarantee that read-access to a particular object in
|
||
<code class="literal">pop</code> "happens after" it has been written in
|
||
<code class="literal">push</code>. This is achieved by writing <code class="literal">head_ </code>
|
||
with "release" and reading it with "acquire". Conversely
|
||
the implementation also ensures that read access to a particular ring element
|
||
"happens before" before rewriting this element with a new value
|
||
by accessing <code class="literal">tail_</code> with appropriate ordering constraints.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h3 class="title">
|
||
<a name="boost_atomic.usage_examples.mp_queue"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.mp_queue" title="Lock-free multi-producer queue">Lock-free multi-producer
|
||
queue</a>
|
||
</h3></div></div></div>
|
||
<div class="toc"><dl class="toc">
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.mp_queue.implementation">Implementation</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.mp_queue.usage">Usage</a></span></dt>
|
||
<dt><span class="section"><a href="usage_examples.html#boost_atomic.usage_examples.mp_queue.discussion">Discussion</a></span></dt>
|
||
</dl></div>
|
||
<p>
|
||
The purpose of the <span class="emphasis"><em>lock-free multi-producer queue</em></span> is
|
||
to allow an arbitrary number of producers to enqueue objects which are retrieved
|
||
and processed in FIFO order by a single consumer.
|
||
</p>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.mp_queue.implementation"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.mp_queue.implementation" title="Implementation">Implementation</a>
|
||
</h4></div></div></div>
|
||
<pre class="programlisting"><span class="keyword">template</span><span class="special"><</span><span class="keyword">typename</span> <span class="identifier">T</span><span class="special">></span>
|
||
<span class="keyword">class</span> <span class="identifier">lockfree_queue</span> <span class="special">{</span>
|
||
<span class="keyword">public</span><span class="special">:</span>
|
||
<span class="keyword">struct</span> <span class="identifier">node</span> <span class="special">{</span>
|
||
<span class="identifier">T</span> <span class="identifier">data</span><span class="special">;</span>
|
||
<span class="identifier">node</span> <span class="special">*</span> <span class="identifier">next</span><span class="special">;</span>
|
||
<span class="special">};</span>
|
||
<span class="keyword">void</span> <span class="identifier">push</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">T</span> <span class="special">&</span><span class="identifier">data</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">node</span> <span class="special">*</span> <span class="identifier">n</span> <span class="special">=</span> <span class="keyword">new</span> <span class="identifier">node</span><span class="special">;</span>
|
||
<span class="identifier">n</span><span class="special">-></span><span class="identifier">data</span> <span class="special">=</span> <span class="identifier">data</span><span class="special">;</span>
|
||
<span class="identifier">node</span> <span class="special">*</span> <span class="identifier">stale_head</span> <span class="special">=</span> <span class="identifier">head_</span><span class="special">.</span><span class="identifier">load</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_relaxed</span><span class="special">);</span>
|
||
<span class="keyword">do</span> <span class="special">{</span>
|
||
<span class="identifier">n</span><span class="special">-></span><span class="identifier">next</span> <span class="special">=</span> <span class="identifier">stale_head</span><span class="special">;</span>
|
||
<span class="special">}</span> <span class="keyword">while</span> <span class="special">(!</span><span class="identifier">head_</span><span class="special">.</span><span class="identifier">compare_exchange_weak</span><span class="special">(</span><span class="identifier">stale_head</span><span class="special">,</span> <span class="identifier">n</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_release</span><span class="special">));</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="identifier">node</span> <span class="special">*</span> <span class="identifier">pop_all</span><span class="special">(</span><span class="keyword">void</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="identifier">T</span> <span class="special">*</span> <span class="identifier">last</span> <span class="special">=</span> <span class="identifier">pop_all_reverse</span><span class="special">(),</span> <span class="special">*</span> <span class="identifier">first</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
|
||
<span class="keyword">while</span><span class="special">(</span><span class="identifier">last</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="identifier">T</span> <span class="special">*</span> <span class="identifier">tmp</span> <span class="special">=</span> <span class="identifier">last</span><span class="special">;</span>
|
||
<span class="identifier">last</span> <span class="special">=</span> <span class="identifier">last</span><span class="special">-></span><span class="identifier">next</span><span class="special">;</span>
|
||
<span class="identifier">tmp</span><span class="special">-></span><span class="identifier">next</span> <span class="special">=</span> <span class="identifier">first</span><span class="special">;</span>
|
||
<span class="identifier">first</span> <span class="special">=</span> <span class="identifier">tmp</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">return</span> <span class="identifier">first</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
|
||
<span class="identifier">lockfree_queue</span><span class="special">()</span> <span class="special">:</span> <span class="identifier">head_</span><span class="special">(</span><span class="number">0</span><span class="special">)</span> <span class="special">{}</span>
|
||
|
||
<span class="comment">// alternative interface if ordering is of no importance</span>
|
||
<span class="identifier">node</span> <span class="special">*</span> <span class="identifier">pop_all_reverse</span><span class="special">(</span><span class="keyword">void</span><span class="special">)</span>
|
||
<span class="special">{</span>
|
||
<span class="keyword">return</span> <span class="identifier">head_</span><span class="special">.</span><span class="identifier">exchange</span><span class="special">(</span><span class="number">0</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">memory_order_consume</span><span class="special">);</span>
|
||
<span class="special">}</span>
|
||
<span class="keyword">private</span><span class="special">:</span>
|
||
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">atomic</span><span class="special"><</span><span class="identifier">node</span> <span class="special">*></span> <span class="identifier">head_</span><span class="special">;</span>
|
||
<span class="special">};</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.mp_queue.usage"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.mp_queue.usage" title="Usage">Usage</a>
|
||
</h4></div></div></div>
|
||
<pre class="programlisting"><span class="identifier">lockfree_queue</span><span class="special"><</span><span class="keyword">int</span><span class="special">></span> <span class="identifier">q</span><span class="special">;</span>
|
||
|
||
<span class="comment">// insert elements</span>
|
||
<span class="identifier">q</span><span class="special">.</span><span class="identifier">push</span><span class="special">(</span><span class="number">42</span><span class="special">);</span>
|
||
<span class="identifier">q</span><span class="special">.</span><span class="identifier">push</span><span class="special">(</span><span class="number">2</span><span class="special">);</span>
|
||
|
||
<span class="comment">// pop elements</span>
|
||
<span class="identifier">lockfree_queue</span><span class="special"><</span><span class="keyword">int</span><span class="special">>::</span><span class="identifier">node</span> <span class="special">*</span> <span class="identifier">x</span> <span class="special">=</span> <span class="identifier">q</span><span class="special">.</span><span class="identifier">pop_all</span><span class="special">()</span>
|
||
<span class="keyword">while</span><span class="special">(</span><span class="identifier">x</span><span class="special">)</span> <span class="special">{</span>
|
||
<span class="identifier">X</span> <span class="special">*</span> <span class="identifier">tmp</span> <span class="special">=</span> <span class="identifier">x</span><span class="special">;</span>
|
||
<span class="identifier">x</span> <span class="special">=</span> <span class="identifier">x</span><span class="special">-></span><span class="identifier">next</span><span class="special">;</span>
|
||
<span class="comment">// process tmp->data, probably delete it afterwards</span>
|
||
<span class="keyword">delete</span> <span class="identifier">tmp</span><span class="special">;</span>
|
||
<span class="special">}</span>
|
||
</pre>
|
||
</div>
|
||
<div class="section">
|
||
<div class="titlepage"><div><div><h4 class="title">
|
||
<a name="boost_atomic.usage_examples.mp_queue.discussion"></a><a class="link" href="usage_examples.html#boost_atomic.usage_examples.mp_queue.discussion" title="Discussion">Discussion</a>
|
||
</h4></div></div></div>
|
||
<p>
|
||
The implementation guarantees that all objects enqueued are processed in
|
||
the order they were enqueued by building a singly-linked list of object
|
||
in reverse processing order. The queue is atomically emptied by the consumer
|
||
(in an operation that is not only lock-free but wait-free) and brought
|
||
into correct order.
|
||
</p>
|
||
<p>
|
||
It must be guaranteed that any access to an object to be enqueued by the
|
||
producer "happens before" any access by the consumer. This is
|
||
assured by inserting objects into the list with <span class="emphasis"><em>release</em></span>
|
||
and dequeuing them with <span class="emphasis"><em>consume</em></span> memory order. It is
|
||
not necessary to use <span class="emphasis"><em>acquire</em></span> memory order in <code class="literal">waitfree_queue::pop_all</code>
|
||
because all operations involved depend on the value of the atomic pointer
|
||
through dereference.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
|
||
<td align="left"></td>
|
||
<td align="right"><div class="copyright-footer">Copyright © 2011 Helge Bahmann<br>Copyright © 2012 Tim Blechmann<br>Copyright © 2013, 2017, 2018, 2020 Andrey
|
||
Semashev<p>
|
||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||
file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
|
||
</p>
|
||
</div></td>
|
||
</tr></table>
|
||
<hr>
|
||
<div class="spirit-nav">
|
||
<a accesskey="p" href="interface.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../atomic.html"><img src="../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="limitations.html"><img src="../../../doc/src/images/next.png" alt="Next"></a>
|
||
</div>
|
||
</body>
|
||
</html>
|