2
0
mirror of https://github.com/boostorg/thread.git synced 2026-01-27 19:32:11 +00:00
Files
thread/doc/mutex_concept.html
Beman Dawes b282e06a90 Initial commit
[SVN r10342]
2001-06-15 15:42:45 +00:00

160 lines
7.7 KiB
HTML

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="keywords" content="threads, BTL, thread library, C++">
<title>Boost.Threads, Mutex Concept</title>
</head>
<body bgcolor="#ffffff" link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%">
<tr>
<td valign="top" width="300">
<h3><IMG height=86 alt="C++ Boost" src="../../../c++boost.gif" width=277></h3>
</td>
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Mutex Concept</h2>
</td>
</tr>
</table>
<hr>
<p>The purpose of a mutex (short for mutual-exclusion) is to serialize access to
a resource shared between multiple threads. The mutex concept formalizes this
idea. A model that implements the mutex concept has two states: locked and
unlocked. Before using a resource that's shared, a thread would lock the mutex model,
insuring that it was the only thread accessing the shared resource at a given
time. When done with the shared resource the thread would unlock the mutex model
allowing another thread to acquire the lock and use the shared resource.</p>
<p>Traditional C thread APIs, such as pthreads or Windows thread APIs, expose methods to
lock and unlock a mutex model. This is a dangerous way to expose the needed functionality
since it's easy to forget to unlock a mutex model that's been locked. When the flow of
control is complex, with multiple return points, the likelihood that you'll forget to
unlock a mutex model becomes even greater. With exceptions it becomes nearly impossible
to insure that you unlock the mutex. Many C++ threading libraries have made use of a
pattern known as <i>Scoped Locking</i><sup><A href="#footnote1">1</A></sup> to help insure
that a programmer did not forget to unlock the mutex model. With this pattern a
<A href="lock_concept.html">lock concept</A> is employed where the lock model's constructor
locks the associated mutex model and the destructor unlocks the mutex model. The
<b>Boost.Threads</b> library takes this pattern to the extreme, where lock concepts are the
only way to lock and unlock a mutex model: lock and unlock methods are not exposed by any
mutex models in <b>Boost.Threads</b>. This helps to insure safe usage patterns, especially
with regard to code that may throw exceptions.</p>
<p>The <b>Boost.Threads</b> library currently defines six mutex models:
<A href="mutex.html">boost::mutex</A>, <A href="mutex.html">boost::try_mutex</A>,
<A href="mutex.html">boost::timed_mutex</A>, <A href="recursive_mutex.html">boost::recursive_mutex</A>,
<A href="recursive_mutex.html">boost::recursive_try_mutex</A> and
<A href="recursive_mutex.html">boost::recursive_timed_mutex</A>.</p>
<h2><a name="LockingStrategies">Locking Strategies</a></h2>
<p>Every mutex model follows one of several locking strategies. These strategies
define the semantics for the locking operation when the calling thread already
owns a lock on the mutex model.</p>
<h3>Recursive</h3>
<p>With a recursive locking strategy when a thread attempts to acquire a lock on
the mutex model for which it already owns a lock the operation returns successfully.
Internally a lock count is maintained and the owning thread must unlock the
mutex model the same number of times that it's locked it before the mutex model's
state returns to unlocked. Since mutex model's in <b>Boost.Threads</b> expose
locking functionality only through lock concepts it can be proven that a thread
will always unlock a mutex model the same number of times that it's locked it.
This helps to eliminate a whole set of errors typically found in traditional
C style APIs.</p>
<p>The <A href="recursive_mutex.html">boost::recursive_mutex</A>,
<A href="recursive_mutex.html">boost::recursive_try_mutex</A>
and <A href="recursive_mutex.html">boost::recursive_timed_mutex</A> use this locking strategy.</p>
<h3>Checked</h3>
<p>With a checked locking strategy when a thread attempts to acquire a lock on
the mutex model for which it already owns a lock the operation will fail with
some sort of error indication. Further, attempts by a thread to unlock a mutex
that was not locked by the thread will also return some sort of error indication.
In <b>Boost.Threads</b> an exception of type <A href="lock_error.html">boost::lock_error</A>
is thrown in these cases.</p>
<h3>Unchecked</h3>
<p>With an unchecked locking strategy when a thread attempts to acquire a lock
on the mutex model for which it already owns a lock the operation will deadlock. In
general this locking strategy is less safe than a checked or recursive strategy,
but it's also a faster strategy and so is employed by many libraries.</p>
<p><b>Boost.Threads</b> does not provide a mutex model that explicitly uses this
strategy.</p>
<h3>Unspecified</h3>
<p>With an unspecified locking strategy when a thread attempts to acquire a lock
on a mutex model for which it already owns a lock the operation results in
<b>undefined behavior</b>. When a mutex model has an unspecified locking strategy the
programmer must assume that the mutex model instead uses an unchecked strategy.</p>
<p>In general a mutex model with an unspecified locking strategy is unsafe, and it
requires programmer discipline to use the mutex model properly. However, this strategy
allows an implementation to be as fast as possible with no restrictions on its implementation.
This is especially true for portable implementations that wrap the native threading support
of a platform. For this reason the <A href="mutex.html">boost::mutex</A>,
<A href="mutex.html">boost::try_mutex</A> and <A href="mutex.html">boost::timed_mutex</A> use
this locking strategy despite the lack of safety.</p>
<h2><a name="SchedulingPolicies">Scheduling Policies</a></h2>
<p>Every mutex model follows one of several scheduling policies. These policies
define the semantics for when a mutex model has more than one thread waiting to
acquire a lock when the mutex model is unlocked. In other words, the policy defines
which thread shall acquire the lock in this case.</p>
<h3>FIFO</h3>
<p>With a FIFO scheduling policy threads waiting for the lock will acquire it in
a first come first serve order (or First In First Out). This can help prevent a
high priority thread from starving lower priority threads that are also waiting
on the mutex lock.</p>
<h3>Priority Driven</h3>
<p>With a Priority Driven scheduling policy the thread with the highest priority
acquires the lock. Note that this means that low-priority threads may never acquire
the lock if the mutex model has high contention and there is always at least one high-priority
thread waiting. This is known as thread starvation. When multiple threads of the same
priority are waiting on the mutex lock one of the other scheduling priorities will
determine which thread shall acquire the lock.</p>
<h3>Undefined</h3>
<p>Threads acquire the lock in no particular order. Users should assume that
low-priority threads may wait indefinitely, and that threads of the same
priority acquire the lock in essentially random order.</p>
<h3>Unspecified</h3>
<p>The mutex model does not specify which scheduling policy is used. The programmer
must assume that an undefined scheduling policy is used. In order to insure
portability, all <b>Boost.Threads</b> mutex models use an unspecified scheduling policy.</p>
<hr>
<h2>Foot Notes</h2>
<p><a name="footnote1"><sup>1</sup></a>&nbsp;Douglas Schmidt, Michael Stal, Hans Rohnert, Frank Buschmann:
<i>Pattern-Oriented Software Architecture - Volume 2 (Patterns for Concurrent
and Networked Objects)</i>, Wiley, 2000.</p>
<hr>
<p><i>Copyright <A href="mailto:williamkempf@hotmail.com">William E. Kempf</A>
2001 all rights reserved.</i></p>
</body>
</html>