boost-react-native-bundle
Version:
Boost library as in https://sourceforge.net/projects/boost/files/boost/1.57.0/
550 lines (541 loc) • 1.5 MB
HTML
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Synchronization</title>
<link rel="stylesheet" href="../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.78.1">
<link rel="home" href="../index.html" title="The Boost C++ Libraries BoostBook Documentation Subset">
<link rel="up" href="../thread.html" title="Chapter 30. Thread 4.4.0">
<link rel="prev" href="ScopedThreads.html" title="Scoped Threads">
<link rel="next" href="thread_local_storage.html" title="Thread Local Storage">
</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="ScopedThreads.html"><img src="../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../thread.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="thread_local_storage.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="thread.synchronization"></a><a class="link" href="synchronization.html" title="Synchronization">Synchronization</a>
</h2></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="synchronization.html#thread.synchronization.tutorial">Tutorial</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.mutex_concepts">Mutex Concepts</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.lock_option">Lock Options</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.lock_guard">Lock Guard</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.with_lock_guard">With Lock Guard</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.lock_concepts">Lock Concepts</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.locks">Lock Types</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.other_locks">Other Lock Types
- EXTENSION</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.lock_functions">Lock functions</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.lock_factories">Lock Factories
- EXTENSION</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.mutex_types">Mutex Types</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.condvar_ref">Condition Variables</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.once">One-time Initialization</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.barriers">Barriers -- EXTENSION</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.latches">Latches -- EXPERIMENTAL</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.executors">Executors and Schedulers
-- EXPERIMENTAL</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.futures">Futures</a></span></dt>
</dl></div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="thread.synchronization.tutorial"></a><a class="link" href="synchronization.html#thread.synchronization.tutorial" title="Tutorial">Tutorial</a>
</h3></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="synchronization.html#thread.synchronization.tutorial.internal_locking">Internal
Locking</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.tutorial.external_locking_____strict_lock__and__externally_locked__classes">External
Locking -- <code class="computeroutput"><span class="identifier">strict_lock</span></code> and
<code class="computeroutput"><span class="identifier">externally_locked</span></code> classes</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.tutorial.with">Executing Around
a Function</a></span></dt>
</dl></div>
<p>
<a href="http://home.roadrunner.com/~hinnant/mutexes/locking.html" target="_top">Handling
mutexes in C++</a> is an excellent tutorial. You need just replace std
and ting by boost.
</p>
<p>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html" target="_top">Mutex,
Lock, Condition Variable Rationale</a> adds rationale for the design
decisions made for mutexes, locks and condition variables.
</p>
<p>
In addition to the C++11 standard locks, Boost.Thread provides other locks
and some utilities that help the user to make their code thread-safe.
</p>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="thread.synchronization.tutorial.internal_locking"></a><a class="link" href="synchronization.html#thread.synchronization.tutorial.internal_locking" title="Internal Locking">Internal
Locking</a>
</h4></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="synchronization.html#thread.synchronization.tutorial.internal_locking.concurrent_threads_of_execution">Concurrent
threads of execution</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.tutorial.internal_locking.internal_locking">Internal
locking</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.tutorial.internal_locking.internal_and_external_locking">Internal
and external locking</a></span></dt>
</dl></div>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
This tutorial is an adaptation of chapter Concurrency of the Object-Oriented
Programming in the BETA Programming Language and of the paper of Andrei
Alexandrescu "Multithreading and the C++ Type System" to the
Boost library.
</p></td></tr>
</table></div>
<div class="section">
<div class="titlepage"><div><div><h5 class="title">
<a name="thread.synchronization.tutorial.internal_locking.concurrent_threads_of_execution"></a><a class="link" href="synchronization.html#thread.synchronization.tutorial.internal_locking.concurrent_threads_of_execution" title="Concurrent threads of execution">Concurrent
threads of execution</a>
</h5></div></div></div>
<p>
Consider, for example, modeling a bank account class that supports simultaneous
deposits and withdrawals from multiple locations (arguably the "Hello,
World" of multithreaded programming).
</p>
<p>
From here a component is a model of the <code class="computeroutput"><span class="identifier">Callable</span></code>
concept.
</p>
<p>
I C++11 (Boost) concurrent execution of a component is obtained by means
of the <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">thread</span></code>(<code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">thread</span></code>):
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">thread</span> <span class="identifier">thread1</span><span class="special">(</span><span class="identifier">S</span><span class="special">);</span>
</pre>
<p>
where <code class="computeroutput"><span class="identifier">S</span></code> is a model of
<code class="computeroutput"><span class="identifier">Callable</span></code>. The meaning
of this expression is that execution of <code class="computeroutput"><span class="identifier">S</span><span class="special">()</span></code> will take place concurrently with the
current thread of execution executing the expression.
</p>
<p>
The following example includes a bank account of a person (Joe) and two
components, one corresponding to a bank agent depositing money in Joe's
account, and one representing Joe. Joe will only be withdrawing money
from the account:
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">BankAccount</span><span class="special">;</span>
<span class="identifier">BankAccount</span> <span class="identifier">JoesAccount</span><span class="special">;</span>
<span class="keyword">void</span> <span class="identifier">bankAgent</span><span class="special">()</span>
<span class="special">{</span>
<span class="keyword">for</span> <span class="special">(</span><span class="keyword">int</span> <span class="identifier">i</span> <span class="special">=</span><span class="number">10</span><span class="special">;</span> <span class="identifier">i</span><span class="special">></span><span class="number">0</span><span class="special">;</span> <span class="special">--</span><span class="identifier">i</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">//...</span>
<span class="identifier">JoesAccount</span><span class="special">.</span><span class="identifier">Deposit</span><span class="special">(</span><span class="number">500</span><span class="special">);</span>
<span class="comment">//...</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">Joe</span><span class="special">()</span> <span class="special">{</span>
<span class="keyword">for</span> <span class="special">(</span><span class="keyword">int</span> <span class="identifier">i</span> <span class="special">=</span><span class="number">10</span><span class="special">;</span> <span class="identifier">i</span><span class="special">></span><span class="number">0</span><span class="special">;</span> <span class="special">--</span><span class="identifier">i</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">//...</span>
<span class="keyword">int</span> <span class="identifier">myPocket</span> <span class="special">=</span> <span class="identifier">JoesAccount</span><span class="special">.</span><span class="identifier">Withdraw</span><span class="special">(</span><span class="number">100</span><span class="special">);</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special"><<</span> <span class="identifier">myPocket</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="comment">//...</span>
<span class="special">}</span>
<span class="special">}</span>
<span class="keyword">int</span> <span class="identifier">main</span><span class="special">()</span> <span class="special">{</span>
<span class="comment">//...</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">thread</span> <span class="identifier">thread1</span><span class="special">(</span><span class="identifier">bankAgent</span><span class="special">);</span> <span class="comment">// start concurrent execution of bankAgent</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">thread</span> <span class="identifier">thread2</span><span class="special">(</span><span class="identifier">Joe</span><span class="special">);</span> <span class="comment">// start concurrent execution of Joe</span>
<span class="identifier">thread1</span><span class="special">.</span><span class="identifier">join</span><span class="special">();</span>
<span class="identifier">thread2</span><span class="special">.</span><span class="identifier">join</span><span class="special">();</span>
<span class="keyword">return</span> <span class="number">0</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>
From time to time, the <code class="computeroutput"><span class="identifier">bankAgent</span></code>
will deposit $500 in <code class="computeroutput"><span class="identifier">JoesAccount</span></code>.
<code class="computeroutput"><span class="identifier">Joe</span></code> will similarly withdraw
$100 from his account. These sentences describe that the <code class="computeroutput"><span class="identifier">bankAgent</span></code> and <code class="computeroutput"><span class="identifier">Joe</span></code>
are executed concurrently.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h5 class="title">
<a name="thread.synchronization.tutorial.internal_locking.internal_locking"></a><a class="link" href="synchronization.html#thread.synchronization.tutorial.internal_locking.internal_locking" title="Internal locking">Internal
locking</a>
</h5></div></div></div>
<p>
The above example works well as long as the components <code class="computeroutput"><span class="identifier">bankAgent</span></code> and <code class="computeroutput"><span class="identifier">Joe</span></code>
doesn't access <code class="computeroutput"><span class="identifier">JoesAccount</span></code>
at the same time. There is, however, no guarantee that this will not
happen. We may use a mutex to guarantee exclusive access to each bank.
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">BankAccount</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">mutex</span> <span class="identifier">mtx_</span><span class="special">;</span>
<span class="keyword">int</span> <span class="identifier">balance_</span><span class="special">;</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">void</span> <span class="identifier">Deposit</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">amount</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">mtx_</span><span class="special">.</span><span class="identifier">lock</span><span class="special">();</span>
<span class="identifier">balance_</span> <span class="special">+=</span> <span class="identifier">amount</span><span class="special">;</span>
<span class="identifier">mtx_</span><span class="special">.</span><span class="identifier">unlock</span><span class="special">();</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">Withdraw</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">amount</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">mtx_</span><span class="special">.</span><span class="identifier">lock</span><span class="special">();</span>
<span class="identifier">balance_</span> <span class="special">-=</span> <span class="identifier">amount</span><span class="special">;</span>
<span class="identifier">mtx_</span><span class="special">.</span><span class="identifier">unlock</span><span class="special">();</span>
<span class="special">}</span>
<span class="keyword">int</span> <span class="identifier">GetBalance</span><span class="special">()</span> <span class="special">{</span>
<span class="identifier">mtx_</span><span class="special">.</span><span class="identifier">lock</span><span class="special">();</span>
<span class="keyword">int</span> <span class="identifier">b</span> <span class="special">=</span> <span class="identifier">balance_</span><span class="special">;</span>
<span class="identifier">mtx_</span><span class="special">.</span><span class="identifier">unlock</span><span class="special">();</span>
<span class="keyword">return</span> <span class="identifier">b</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
Execution of the <code class="computeroutput"><span class="identifier">Deposit</span></code>
and <code class="computeroutput"><span class="identifier">Withdraw</span></code> operations
will no longer be able to make simultaneous access to balance.
</p>
<p>
A mutex is a simple and basic mechanism for obtaining synchronization.
In the above example it is relatively easy to be convinced that the synchronization
works correctly (in the absence of exception). In a system with several
concurrent objects and several shared objects, it may be difficult to
describe synchronization by means of mutexes. Programs that make heavy
use of mutexes may be difficult to read and write. Instead, we shall
introduce a number of generic classes for handling more complicated forms
of synchronization and communication.
</p>
<p>
With the RAII idiom we can simplify a lot this using the scoped locks.
In the code below, guard's constructor locks the passed-in object <code class="computeroutput"><span class="identifier">mtx_</span></code>, and guard's destructor unlocks
<code class="computeroutput"><span class="identifier">mtx_</span></code>.
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">BankAccount</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">mutex</span> <span class="identifier">mtx_</span><span class="special">;</span> <span class="comment">// explicit mutex declaration </span>
<span class="keyword">int</span> <span class="identifier">balance_</span><span class="special">;</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">void</span> <span class="identifier">Deposit</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">amount</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">lock_guard</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">guard</span><span class="special">(</span><span class="identifier">mtx_</span><span class="special">);</span>
<span class="identifier">balance_</span> <span class="special">+=</span> <span class="identifier">amount</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">Withdraw</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">amount</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">lock_guard</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">guard</span><span class="special">(</span><span class="identifier">mtx_</span><span class="special">);</span>
<span class="identifier">balance_</span> <span class="special">-=</span> <span class="identifier">amount</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">int</span> <span class="identifier">GetBalance</span><span class="special">()</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">lock_guard</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">guard</span><span class="special">(</span><span class="identifier">mtx_</span><span class="special">);</span>
<span class="keyword">return</span> <span class="identifier">balance_</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
The object-level locking idiom doesn't cover the entire richness of a
threading model. For example, the model above is quite deadlock-prone
when you try to coordinate multi-object transactions. Nonetheless, object-level
locking is useful in many cases, and in combination with other mechanisms
can provide a satisfactory solution to many threaded access problems
in object-oriented programs.
</p>
</div>
<div class="section">
<div class="titlepage"><div><div><h5 class="title">
<a name="thread.synchronization.tutorial.internal_locking.internal_and_external_locking"></a><a class="link" href="synchronization.html#thread.synchronization.tutorial.internal_locking.internal_and_external_locking" title="Internal and external locking">Internal
and external locking</a>
</h5></div></div></div>
<p>
The BankAccount class above uses internal locking. Basically, a class
that uses internal locking guarantees that any concurrent calls to its
public member functions don't corrupt an instance of that class. This
is typically ensured by having each public member function acquire a
lock on the object upon entry. This way, for any given object of that
class, there can be only one member function call active at any moment,
so the operations are nicely serialized.
</p>
<p>
This approach is reasonably easy to implement and has an attractive simplicity.
Unfortunately, "simple" might sometimes morph into "simplistic."
</p>
<p>
Internal locking is insufficient for many real-world synchronization
tasks. Imagine that you want to implement an ATM withdrawal transaction
with the BankAccount class. The requirements are simple. The ATM transaction
consists of two withdrawals-one for the actual money and one for the
$2 commission. The two withdrawals must appear in strict sequence; that
is, no other transaction can exist between them.
</p>
<p>
The obvious implementation is erratic:
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">ATMWithdrawal</span><span class="special">(</span><span class="identifier">BankAccount</span><span class="special">&</span> <span class="identifier">acct</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">sum</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">acct</span><span class="special">.</span><span class="identifier">Withdraw</span><span class="special">(</span><span class="identifier">sum</span><span class="special">);</span>
<span class="comment">// preemption possible</span>
<span class="identifier">acct</span><span class="special">.</span><span class="identifier">Withdraw</span><span class="special">(</span><span class="number">2</span><span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
The problem is that between the two calls above, another thread can perform
another operation on the account, thus breaking the second design requirement.
</p>
<p>
In an attempt to solve this problem, let's lock the account from the
outside during the two operations:
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">ATMWithdrawal</span><span class="special">(</span><span class="identifier">BankAccount</span><span class="special">&</span> <span class="identifier">acct</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">sum</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">lock_guard</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">guard</span><span class="special">(</span><span class="identifier">acct</span><span class="special">.</span><span class="identifier">mtx_</span><span class="special">);</span> <span class="number">1</span>
<span class="identifier">acct</span><span class="special">.</span><span class="identifier">Withdraw</span><span class="special">(</span><span class="identifier">sum</span><span class="special">);</span>
<span class="identifier">acct</span><span class="special">.</span><span class="identifier">Withdraw</span><span class="special">(</span><span class="number">2</span><span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
Notice that the code above doesn't compile, the <code class="computeroutput"><span class="identifier">mtx_</span></code>
field is private. We have two possibilities:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
make <code class="computeroutput"><span class="identifier">mtx_</span></code> public
which seems odd
</li>
<li class="listitem">
make the <code class="computeroutput"><span class="identifier">BankAccount</span></code>
lockable by adding the lock/unlock functions
</li>
</ul></div>
<p>
We can add these functions explicitly
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">BankAccount</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">mutex</span> <span class="identifier">mtx_</span><span class="special">;</span>
<span class="keyword">int</span> <span class="identifier">balance_</span><span class="special">;</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">void</span> <span class="identifier">Deposit</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">amount</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">lock_guard</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">guard</span><span class="special">(</span><span class="identifier">mtx_</span><span class="special">);</span>
<span class="identifier">balance_</span> <span class="special">+=</span> <span class="identifier">amount</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">Withdraw</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">amount</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">lock_guard</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">guard</span><span class="special">(</span><span class="identifier">mtx_</span><span class="special">);</span>
<span class="identifier">balance_</span> <span class="special">-=</span> <span class="identifier">amount</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="identifier">mtx_</span><span class="special">.</span><span class="identifier">lock</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">mtx_</span><span class="special">.</span><span class="identifier">unlock</span><span class="special">();</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
or inheriting from a class which add these lockable functions.
</p>
<p>
The <code class="computeroutput"><span class="identifier">basic_lockable_adapter</span></code>
class helps to define the <code class="computeroutput"><span class="identifier">BankAccount</span></code>
class as
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">BankAccount</span>
<span class="special">:</span> <span class="keyword">public</span> <span class="identifier">basic_lockable_adapter</span><span class="special"><</span><span class="identifier">mutex</span><span class="special">></span>
<span class="special">{</span>
<span class="keyword">int</span> <span class="identifier">balance_</span><span class="special">;</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">void</span> <span class="identifier">Deposit</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">amount</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">lock_guard</span><span class="special"><</span><span class="identifier">BankAccount</span><span class="special">></span> <span class="identifier">guard</span><span class="special">(*</span><span class="keyword">this</span><span class="special">);</span>
<span class="identifier">balance_</span> <span class="special">+=</span> <span class="identifier">amount</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">Withdraw</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">amount</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">lock_guard</span><span class="special"><</span><span class="identifier">BankAccount</span><span class="special">></span> <span class="identifier">guard</span><span class="special">(*</span><span class="keyword">this</span><span class="special">);</span>
<span class="identifier">balance_</span> <span class="special">-=</span> <span class="identifier">amount</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">int</span> <span class="identifier">GetBalance</span><span class="special">()</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">lock_guard</span><span class="special"><</span><span class="identifier">BankAccount</span><span class="special">></span> <span class="identifier">guard</span><span class="special">(*</span><span class="keyword">this</span><span class="special">);</span>
<span class="keyword">return</span> <span class="identifier">balance_</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
and the code that doesn't compiles becomes
</p>
<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">ATMWithdrawal</span><span class="special">(</span><span class="identifier">BankAccount</span><span class="special">&</span> <span class="identifier">acct</span><span class="special">,</span> <span class="keyword">int</span> <span class="identifier">sum</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">boost</span><span class="special">::</span><span class="identifier">lock_guard</span><span class="special"><</span><span class="identifier">BankAccount</span><span class="special">></span> <span class="identifier">guard</span><span class="special">(</span><span class="identifier">acct</span><span class="special">);</span>
<span class="identifier">acct</span><span class="special">.</span><span class="identifier">Withdraw</span><span class="special">(</span><span class="identifier">sum</span><span class="special">);</span>
<span class="identifier">acct</span><span class="special">.</span><span class="identifier">Withdraw</span><span class="special">(</span><span class="number">2</span><span class="special">);</span>
<span class="special">}</span>
</pre>
<p>
Notice that now acct is being locked by Withdraw after it has already
been locked by guard. When running such code, one of two things happens.
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
Your mutex implementation might support the so-called recursive mutex
semantics. This means that the same thread can lock the same mutex
several times successfully. In this case, the implementation works
but has a performance overhead due to unnecessary locking. (The locking/unlocking
sequence in the two Withdraw calls is not needed but performed anyway-and
that costs time.)
</li>
<li class="listitem">
Your mutex implementation might not support recursive locking, which
means that as soon as you try to acquire it the second time, it blocks-so
the ATMWithdrawal function enters the dreaded deadlock.
</li>
</ul></div>
<p>
As <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">mutex</span></code> is not recursive, we need to
use its recursive version <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">recursive_mutex</span></code>.
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">BankAccount</span>
<span class="special">:</span> <span class="keyword">public</span> <span class="identifier">basic_lockable_adapter</span><span class="special"><</span><span class="identifier">recursive_mutex</span><span class="special">></span>
<span class="special">{</span>
<span class="comment">// ...</span>
<span class="special">};</span>
</pre>
<p>
The caller-ensured locking approach is more flexible and the most efficient,
but very dangerous. In an implementation using caller-ensured locking,
BankAccount still holds a mutex, but its member functions don't manipulate
it at all. Deposit and Withdraw are not thread-safe anymore. Instead,
the client code is responsible for locking BankAccount properly.
</p>
<pre class="programlisting"><span class="keyword">class</span> <span class="identifier">BankAccount</span>
<span class="special">:</span> <span class="keyword">public</span> <span class="identifier">basic_lockable_adapter</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="special">{</span>
<span class="keyword">int</span> <span class="identifier">balance_</span><span class="special">;</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">void</span> <span class="identifier">Deposit</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">amount</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">balance_</span> <span class="special">+=</span> <span class="identifier">amount</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">void</span> <span class="identifier">Withdraw</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">amount</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">balance_</span> <span class="special">-=</span> <span class="identifier">amount</span><span class="special">;</span>
<span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
Obviously, the caller-ensured locking approach has a safety problem.
BankAccount's implementation code is finite, and easy to reach and maintain,
but there's an unbounded amount of client code that manipulates BankAccount
objects. In designing applications, it's important to differentiate between
requirements imposed on bounded code and unbounded code. If your class
makes undue requirements on unbounded code, that's usually a sign that
encapsulation is out the window.
</p>
<p>
To conclude, if in designing a multi-threaded class you settle on internal
locking, you expose yourself to inefficiency or deadlocks. On the other
hand, if you rely on caller-provided locking, you make your class error-prone
and difficult to use. Finally, external locking completely avoids the
issue by leaving it all to the client code.
</p>
</div>
</div>
<div class="section">
<div class="titlepage"><div><div><h4 class="title">
<a name="thread.synchronization.tutorial.external_locking_____strict_lock__and__externally_locked__classes"></a><a class="link" href="synchronization.html#thread.synchronization.tutorial.external_locking_____strict_lock__and__externally_locked__classes" title="External Locking -- strict_lock and externally_locked classes">External
Locking -- <code class="computeroutput"><span class="identifier">strict_lock</span></code> and
<code class="computeroutput"><span class="identifier">externally_locked</span></code> classes</a>
</h4></div></div></div>
<div class="toc"><dl class="toc">
<dt><span class="section"><a href="synchronization.html#thread.synchronization.tutorial.external_locking_____strict_lock__and__externally_locked__classes.locks_as_permits">Locks
as permits</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.tutorial.external_locking_____strict_lock__and__externally_locked__classes.improving_external_locking">Improving
External Locking</a></span></dt>
<dt><span class="section"><a href="synchronization.html#thread.synchronization.tutorial.external_locking_____strict_lock__and__externally_locked__classes.allowing_other_strict_locks">Allowing
other strict locks</a></span></dt>
</dl></div>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
This tutorial is an adaptation of the paper by Andrei Alexandrescu "Multithreading
and the C++ Type System" to the Boost library.
</p></td></tr>
</table></div>
<div class="section">
<div class="titlepage"><div><div><h5 class="title">
<a name="thread.synchronization.tutorial.external_locking_____strict_lock__and__externally_locked__classes.locks_as_permits"></a><a class="link" href="synchronization.html#thread.synchronization.tutorial.external_locking_____strict_lock__and__externally_locked__classes.locks_as_permits" title="Locks as permits">Locks
as permits</a>
</h5></div></div></div>
<p>
So what to do? Ideally, the BankAccount class should do the following:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
Support both locking models (internal and external).
</li>
<li class="listitem">
Be efficient; that is, use no unnecessary locking.
</li>
<li class="listitem">
Be safe; that is, BankAccount objects cannot be manipulated without
appropriate locking.
</li>
</ul></div>
<p>
Let's make a worthwhile observation: Whenever you lock a BankAccount,
you do so by using a <code class="computeroutput"><span class="identifier">lock_guard</span><span class="special"><</span><span class="identifier">BankAccount</span><span class="special">></span></code> object. Turning this statement around,
wherever there's a <code class="computeroutput"><span class="identifier">lock_guard</span><span class="special"><</span><span class="identifier">BankAccount</span><span class="special">></span></code>, there's also a locked <code class="computeroutput"><span class="identifier">BankAccount</span></code> somewhere. Thus, you can
think of-and use-a <code class="computeroutput"><span class="identifier">lock_guard</span><span class="special"><</span><span class="identifier">BankAccount</span><span class="special">></span></code> object as a permit. Owning a <code class="computeroutput"><span class="identifier">lock_guard</span><span class="special"><</span><span class="identifier">BankAccount</span><span class="special">></span></code>
gives you rights to do certain things. The <code class="computeroutput"><span class="identifier">lock_guard</span><span class="special"><</span><span class="identifier">BankAccount</span><span class="special">></span></code> object should not be copied or aliased
(it's not a transmissible permit).
</p>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
As long as a permit is still alive, the <code class="computeroutput"><span class="identifier">BankAccount</span></code>
object stays locked.
</li>
<li class="listitem">
When the <code class="computeroutput"><span class="identifier">lock_guard</span><span class="special"><</span><span class="identifier">BankAccount</span><span class="special">></span></code> is destroyed, the <code class="computeroutput"><span class="identifier">BankAccount</span></code>'s mutex is released.
</li>
</ol></div>
<p>
The net effect is that at any point in your code, having access to a
<code class="computeroutput"><span class="identifier">lock_guard</span><span class="special"><</span><span class="identifier">BankAccount</span><span class="special">></span></code>
object guarantees that a <code class="computeroutput"><span class="identifier">BankAccount</span></code>
is locked. (You don't know exactly which <code class="computeroutput"><span class="identifier">BankAccount</span></code>
is locked, however-an issue that we'll address soon.)
</p>
<p>
For now, let's make a couple of enhancements to the <code class="computeroutput"><span class="identifier">lock_guard</span></code>
class template defined in Boost.Thread. We'll call the enhanced version
<code class="computeroutput"><span class="identifier">strict_lock</span></code>. Essentially,
a <code class="computeroutput"><span class="identifier">strict_lock</span></code>'s role
is only to live on the stack as an automatic variable. <code class="computeroutput"><span class="identifier">strict_lock</span></code> must adhere to a non-copy
and non-alias policy. <code class="computeroutput"><span class="identifier">strict_lock</span></code>
disables copying by making the copy constructor and the assignment operator
private.
</p>
<pre class="programlisting"><span class="keyword">template</span> <span class="special"><</span><span class="keyword">typename</span> <span class="identifier">Lockable</span><span class="special">></span>
<span class="keyword">class</span> <span class="identifier">strict_lock</span> <span class="special">{</span>
<span class="keyword">public</span><span class="special">:</span>
<span class="keyword">typedef</span> <span class="identifier">Lockable</span> <span class="identifier">lockable_type</span><span class="special">;</span>
<span class="keyword">explicit</span> <span class="identifier">strict_lock</span><span class="special">(</span><span class="identifier">lockable_type</span><span class="special">&</span> <span class="identifier">obj</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">obj_</span><span class="special">(</span><span class="identifier">obj</span><span class="special">)</span> <span class="special">{</span>
<span class="identifier">obj</span><span class="special">.</span><span class="identifier">lock</span><span class="special">();</span> <span class="comment">// locks on construction</span>
<span class="special">}</span>
<span class="identifier">strict_lock</span><span class="special">()</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>
<span class="identifier">strict_lock</span><span class="special">(</span><span class="identifier">strict_lock</span> <span class="keyword">const</span><span class="special">&)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>
<span class="identifier">strict_lock</span><span class="special">&</span> <span class="keyword">operator</span><span class="special">=(</span><span class="identifier">strict_lock</span> <span class="keyword">const</span><span class="special">&)</span> <span class="special">=</span> <span class="keyword">delete</span><span class="special">;</span>
<span class="special">~</span><span class="identifier">strict_lock</span><span class="special">()</span> <span class="special">{</span> <span class="identifier">obj_</span><span class="special">.</span><span class="identifier">unlock</span><span class="special">();</span> <span class="special">}</span> <span class="comment">// unlocks on destruction </span>
<span class="keyword">bool</span> <span class="identifier">owns_lock</span><span class="special">(</span><span class="identifier">mutex_type</span> <span class="keyword">const</span><span class="special">*</span> <span class="identifier">l</span><span class="special">)</span> <span class="keyword">const</span> <span class="keyword">noexcept</span> <span class="comment">// strict lockers specific function </span>
<span class="special">{</span>
<span class="keyword">return</span> <span class="identifier">l</span> <span class="special">==</span> <span class="special">&</span><span class="identifier">obj_</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">private</span><span class="special">:</span>
<span class="identifier">lockable_type</span><span class="special">&</span> <span class="identifier">obj_</span><span class="special">;</span>
<span class="special">};</span>
</pre>
<p>
Silence can be sometimes louder than words-what's forbidden to do with
a <code class="computeroutput"><span class="identifier">strict_lock</span></code> is as important
as what you can do. Let's see what you can and what you cannot do with
a <code class="computeroutput"><span class="identifier">strict_lock</span></code> instantiation:
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc;