mirror of
https://github.com/boostorg/thread.git
synced 2026-01-23 18:12:12 +00:00
2287 lines
87 KiB
XML
2287 lines
87 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
|
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
|
|
<!ENTITY % threads.entities SYSTEM "entities.xml">
|
|
%threads.entities;
|
|
]>
|
|
<section id="threads.concepts" last-revision="$Date$">
|
|
<title>Concepts</title>
|
|
|
|
<para>&Boost.Threads; currently supports two types of mutex concepts:
|
|
ordinary <link linkend="threads.concepts.mutexes">Mutexes</link>,
|
|
which allow only one thread at a time to access a resource, and
|
|
<link linkend="threads.concepts.read-write-mutexes">Read/Write Mutexes</link>,
|
|
which allow only one thread at a time to access a resource when it is
|
|
being modified (the "Write" part of Read/Write), but allows multiple threads
|
|
to access a resource when it is only being referenced (the "Read" part of
|
|
Read/Write).</para>
|
|
|
|
<section id="threads.concepts.mutexes">
|
|
<title>Mutexes</title>
|
|
|
|
<note>Certain changes to the mutexes and lock concepts are
|
|
currently under discussion. In particular, the combination of
|
|
the multiple lock concepts into a single lock concept
|
|
is likely, and the combination of the multiple mutex
|
|
concepts into a single mutex concept is also possible.</note>
|
|
|
|
<para>A mutex (short for mutual-exclusion) object is used to serialize
|
|
access to a resource shared between multiple threads. The
|
|
<link linkend="threads.concepts.Mutex">Mutex</link> concept, with
|
|
<link linkend="threads.concepts.TryMutex">TryMutex</link> and
|
|
<link linkend="threads.concepts.TimedMutex">TimedMutex</link> refinements,
|
|
formalize the requirements. A model that implements Mutex and its
|
|
refinements has two states: <emphasis role="bold">locked</emphasis> and
|
|
<emphasis role="bold">unlocked</emphasis>. Before using a shared resource, a
|
|
thread locks a &Boost.Threads; mutex object
|
|
(an object whose type is a model of
|
|
<link linkend="threads.concepts.Mutex">Mutex</link> or one of it's
|
|
refinements), ensuring
|
|
<link linkend="threads.glossary.thread-safe">thread-safe</link> access to
|
|
the shared resource. When use of the shared resource is complete, the thread
|
|
unlocks the mutex object, allowing another thread to acquire the lock and
|
|
use the shared resource.</para>
|
|
<para>Traditional C thread APIs, like POSIX threads or the Windows thread
|
|
APIs, expose functions to lock and unlock a mutex object. This is dangerous
|
|
since it's easy to forget to unlock a locked mutex. When the flow of control
|
|
is complex, with multiple return points, the likelihood of forgetting to
|
|
unlock a mutex object becomes even greater. When exceptions are thrown,
|
|
it becomes nearly impossible to ensure that the mutex object is unlocked
|
|
properly when using these traditional API's. The result is
|
|
<link linkend="threads.glossary.deadlock">deadlock</link>.</para>
|
|
<para>Many C++ threading libraries use a pattern known as <emphasis>Scoped
|
|
Locking</emphasis> &cite.SchmidtStalRohnertBuschmann; to free the programmer from
|
|
the need to explicitly lock and unlock mutex objects. With this pattern, a
|
|
<link linkend="threads.concepts.lock-concepts">Lock</link> concept is employed where
|
|
the lock object's constructor locks the associated mutex object and the
|
|
destructor automatically does the unlocking. The
|
|
&Boost.Threads; library takes this pattern to
|
|
the extreme in that Lock concepts are the only way to lock and unlock a
|
|
mutex object: lock and unlock functions are not exposed by any
|
|
&Boost.Threads; mutex objects. This helps to
|
|
ensure safe usage patterns, especially when code throws exceptions.</para>
|
|
|
|
<section id="threads.concepts.locking-strategies">
|
|
<title>Locking Strategies</title>
|
|
|
|
<para>Every mutex object 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 object.</para>
|
|
|
|
<section id="threads.concepts.recursive-locking-strategy">
|
|
<title>Recursive Locking Strategy</title>
|
|
|
|
<para>With a recursive locking strategy, when a thread attempts to acquire
|
|
a lock on the mutex object for which it already owns a lock, the operation
|
|
is successful. Note the distinction between a thread, which may have
|
|
multiple locks outstanding on a recursive mutex object, and a lock object,
|
|
which even for a recursive mutex object cannot have any of its lock
|
|
functions called multiple times without first calling unlock.</para>
|
|
|
|
<para>Internally a lock count is maintained and the owning thread must
|
|
unlock the mutex object the same number of times that it locked it before
|
|
the mutex object's state returns to unlocked. Since mutex objects in
|
|
&Boost.Threads; expose locking
|
|
functionality only through lock concepts, a thread will always unlock a
|
|
mutex object the same number of times that it locked it. This helps to
|
|
eliminate a whole set of errors typically found in traditional C style
|
|
thread APIs.</para>
|
|
|
|
<para>Classes <classname>boost::recursive_mutex</classname>,
|
|
<classname>boost::recursive_try_mutex</classname> and
|
|
<classname>boost::recursive_timed_mutex</classname> use this locking
|
|
strategy.</para>
|
|
</section>
|
|
|
|
<section id="threads.concepts.checked-locking-strategy">
|
|
<title>Checked Locking Strategy</title>
|
|
|
|
<para>With a checked locking strategy, when a thread attempts to acquire a
|
|
lock on the mutex object for which the thread already owns a lock, the
|
|
operation will fail with some sort of error indication. Further, attempts
|
|
by a thread to unlock a mutex object that was not locked by the thread
|
|
will also return some sort of error indication. In
|
|
&Boost.Threads;, an exception of type
|
|
<classname>boost::lock_error</classname>
|
|
would be thrown in these cases.</para>
|
|
|
|
<para>&Boost.Threads; does not currently
|
|
provide any mutex objects that use this strategy.</para>
|
|
</section>
|
|
|
|
<section id="threads.concepts.unchecked-locking-strategy">
|
|
<title>Unchecked Locking Strategy</title>
|
|
|
|
<para>With an unchecked locking strategy, when a thread attempts to acquire
|
|
a lock on a mutex object for which the thread already owns a lock the
|
|
operation will
|
|
<link linkend="threads.glossary.deadlock">deadlock</link>. 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.</para>
|
|
|
|
<para>&Boost.Threads; does not currently
|
|
provide any mutex objects that use this strategy.</para>
|
|
</section>
|
|
|
|
<section id="threads.concepts.unspecified-locking-strategy">
|
|
<title>Unspecified Locking Strategy</title>
|
|
|
|
<para>With an unspecified locking strategy, when a thread attempts to
|
|
acquire a lock on a mutex object for which the thread already owns a lock
|
|
the operation results in
|
|
<link linkend="threads.glossary.undefined-behavior">undefined behavior</link>.
|
|
</para>
|
|
|
|
<para>In general a mutex object with an unspecified locking strategy is
|
|
unsafe, and it requires programmer discipline to use the mutex object
|
|
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 classes
|
|
<classname>boost::mutex</classname>,
|
|
<classname>boost::try_mutex</classname> and
|
|
<classname>boost::timed_mutex</classname> use this locking strategy
|
|
despite the lack of safety.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="threads.concepts.sheduling-policies">
|
|
<title>Scheduling Policies</title>
|
|
|
|
<para>Every mutex object follows one of several scheduling policies. These
|
|
policies define the semantics when the mutex object is unlocked and there is
|
|
more than one thread waiting to acquire a lock. In other words, the policy
|
|
defines which waiting thread shall acquire the lock.</para>
|
|
|
|
<section id="threads.concepts.FIFO-scheduling-policy">
|
|
<title>FIFO Scheduling Policy</title>
|
|
|
|
<para>With a FIFO ("First In First Out") scheduling policy, threads waiting
|
|
for the lock will acquire it in a first-come-first-served order.
|
|
This can help prevent a high priority thread from starving lower priority
|
|
threads that are also waiting on the mutex object's lock.</para>
|
|
</section>
|
|
|
|
<section id="threads.concepts.priority-driven-scheduling-policy">
|
|
<title>Priority Driven Policy</title>
|
|
|
|
<para>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 object 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 object's lock one of the other scheduling priorities
|
|
will determine which thread shall acquire the lock.</para>
|
|
</section>
|
|
|
|
<section id="threads.concepts.unspecified-scheduling-policy">
|
|
<title>Unspecified Policy</title>
|
|
|
|
<para>The mutex object does not specify a scheduling policy. In order to
|
|
ensure portability, all &Boost.Threads;
|
|
mutex objects use an unspecified scheduling policy.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="threads.concepts.mutex-concepts">
|
|
<title>Mutex Concepts</title>
|
|
|
|
<section id="threads.concepts.Mutex">
|
|
<title>Mutex Concept</title>
|
|
|
|
<para>A Mutex object has two states: locked and unlocked. Mutex object
|
|
state can only be determined by a lock object meeting the
|
|
appropriate lock concept requirements
|
|
and constructed for the Mutex object.</para>
|
|
|
|
<para>A Mutex is
|
|
<ulink url="../../libs/utility/utility.htm#Class%20noncopyable">
|
|
NonCopyable</ulink>.</para>
|
|
<para>For a Mutex type <code>M</code>
|
|
and an object <code>m</code> of that type,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>Mutex Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>M m;</entry>
|
|
<entry><para>Constructs a mutex object m.</para>
|
|
<para>Postcondition: m is unlocked.</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry>(&m)->~M();</entry>
|
|
<entry>Precondition: m is unlocked. Destroys a mutex object
|
|
m.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>M::scoped_lock</entry>
|
|
<entry>A model of
|
|
<link linkend="threads.concepts.ScopedLock">ScopedLock</link>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.TryMutex">
|
|
<title>TryMutex Concept</title>
|
|
|
|
<para>A TryMutex is a refinement of
|
|
<link linkend="threads.concepts.Mutex">Mutex</link>.
|
|
For a TryMutex type <code>M</code>
|
|
and an object <code>m</code> of that type,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>TryMutex Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>M::scoped_try_lock</entry>
|
|
<entry>A model of
|
|
<link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.TimedMutex">
|
|
<title>TimedMutex Concept</title>
|
|
|
|
<para>A TimedMutex is a refinement of
|
|
<link linkend="threads.concepts.TryMutex">TryMutex</link>.
|
|
For a TimedMutex type <code>M</code>
|
|
and an object <code>m</code> of that type,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>TimedMutex Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>M::scoped_timed_lock</entry>
|
|
<entry>A model of
|
|
<link
|
|
linkend="threads.concepts.ScopedTimedLock">ScopedTimedLock</link>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="threads.concepts.mutex-models">
|
|
<title>Mutex Models</title>
|
|
|
|
<para>&Boost.Threads; currently supplies six models of
|
|
<link linkend="threads.concepts.Mutex">Mutex</link>
|
|
and its refinements.</para>
|
|
|
|
<table>
|
|
<title>Mutex Models</title>
|
|
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Concept</entry>
|
|
<entry>Refines</entry>
|
|
<entry>Models</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.Mutex">Mutex</link></entry>
|
|
<entry></entry>
|
|
<entry>
|
|
<para><classname>boost::mutex</classname></para>
|
|
<para><classname>boost::recursive_mutex</classname></para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.TryMutex">TryMutex</link></entry>
|
|
<entry><link linkend="threads.concepts.Mutex">Mutex</link></entry>
|
|
<entry>
|
|
<para><classname>boost::try_mutex</classname></para>
|
|
<para><classname>boost::recursive_try_mutex</classname></para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.TimedMutex">TimedMutex</link></entry>
|
|
<entry><link linkend="threads.concepts.TryMutex">TryMutex</link></entry>
|
|
<entry>
|
|
<para><classname>boost::timed_mutex</classname></para>
|
|
<para><classname>boost::recursive_timed_mutex</classname></para>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.lock-concepts">
|
|
<title>Lock Concepts</title>
|
|
|
|
<para>A lock object provides a safe means for locking and unlocking a mutex
|
|
object (an object whose type is a model of <link
|
|
linkend="threads.concepts.Mutex">Mutex</link> or one of its refinements). In
|
|
other words they are an implementation of the <emphasis>Scoped
|
|
Locking</emphasis> &cite.SchmidtStalRohnertBuschmann; pattern. The <link
|
|
linkend="threads.concepts.ScopedLock">ScopedLock</link>,
|
|
<link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link>, and
|
|
<link linkend="threads.concepts.ScopedTimedLock">ScopedTimedLock</link>
|
|
concepts formalize the requirements.</para>
|
|
<para>Lock objects are constructed with a reference to a mutex object and
|
|
typically acquire ownership of the mutex object by setting its state to
|
|
locked. They also ensure ownership is relinquished in the destructor. Lock
|
|
objects also expose functions to query the lock status and to manually lock
|
|
and unlock the mutex object.</para>
|
|
<para>Lock objects are meant to be short lived, expected to be used at block
|
|
scope only. The lock objects are not <link
|
|
linkend="threads.glossary.thread-safe">thread-safe</link>. Lock objects must
|
|
maintain state to indicate whether or not they've been locked and this state
|
|
is not protected by any synchronization concepts. For this reason a lock
|
|
object should never be shared between multiple threads.</para>
|
|
|
|
<section id="threads.concepts.Lock">
|
|
<title>Lock Concept</title>
|
|
|
|
<para>For a Lock type <code>L</code>
|
|
and an object <code>lk</code>
|
|
and const object <code>clk</code> of that type,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>Lock Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>(&lk)->~L();</code></entry>
|
|
<entry><code>if (locked()) unlock();</code></entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>(&clk)->operator const void*()</code></entry>
|
|
<entry>Returns type void*, non-zero if the associated mutex
|
|
object has been locked by <code>clk</code>, otherwise 0.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>clk.locked()</code></entry>
|
|
<entry>Returns a <code>bool</code>, <code>(&clk)->operator
|
|
const void*() != 0</code></entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>lk.lock()</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if <code>locked()</code>.</para>
|
|
|
|
<para>If the associated mutex object is
|
|
already locked by some other thread, places the current thread in the
|
|
<link linkend="threads.glossary.thread-state">Blocked</link> state until
|
|
the associated mutex is unlocked, after which the current thread
|
|
is placed in the <link
|
|
linkend="threads.glossary.thread-state">Ready</link> state,
|
|
eventually to be returned to the <link
|
|
linkend="threads.glossary.thread-state">Running</link> state. If
|
|
the associated mutex object is already locked by the same thread
|
|
the behavior is dependent on the <link
|
|
linkend="threads.concepts.locking-strategies">locking
|
|
strategy</link> of the associated mutex object.</para>
|
|
|
|
<para>Postcondition: <code>locked() == true</code></para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>lk.unlock()</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if <code>!locked()</code>.</para>
|
|
|
|
<para>Unlocks the associated mutex.</para>
|
|
|
|
<para>Postcondition: <code>!locked()</code></para></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.ScopedLock">
|
|
<title>ScopedLock Concept</title>
|
|
|
|
<para>A ScopedLock is a refinement of <link
|
|
linkend="threads.concepts.Lock">Lock</link>.
|
|
For a ScopedLock type <code>L</code>
|
|
and an object <code>lk</code> of that type,
|
|
and an object <code>m</code> of a type meeting the
|
|
<link linkend="threads.concepts.Mutex">Mutex</link> requirements,
|
|
and an object <code>b</code> of type <code>bool</code>,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>ScopedLock Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>L lk(m);</code></entry>
|
|
<entry>Constructs an object <code>lk</code>, and associates mutex
|
|
object <code>m</code> with it, then calls
|
|
<code>lock()</code></entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>L lk(m,b);</code></entry>
|
|
<entry>Constructs an object <code>lk</code>, and associates mutex
|
|
object <code>m</code> with it, then if <code>b</code>, calls
|
|
<code>lock()</code></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.TryLock">
|
|
<title>TryLock Concept</title>
|
|
|
|
<para>A TryLock is a refinement of <link
|
|
linkend="threads.concepts.Lock">Lock</link>.
|
|
For a TryLock type <code>L</code>
|
|
and an object <code>lk</code> of that type,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>TryLock Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>lk.try_lock()</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if locked().</para>
|
|
|
|
<para>Makes a
|
|
non-blocking attempt to lock the associated mutex object,
|
|
returning <code>true</code> if the lock attempt is successful,
|
|
otherwise <code>false</code>. If the associated mutex object is
|
|
already locked by the same thread the behavior is dependent on the
|
|
<link linkend="threads.concepts.locking-strategies">locking
|
|
strategy</link> of the associated mutex object.</para>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.ScopedTryLock">
|
|
<title>ScopedTryLock Concept</title>
|
|
|
|
<para>A ScopedTryLock is a refinement of <link
|
|
linkend="threads.concepts.TryLock">TryLock</link>.
|
|
For a ScopedTryLock type <code>L</code>
|
|
and an object <code>lk</code> of that type,
|
|
and an object <code>m</code> of a type meeting the
|
|
<link linkend="threads.concepts.TryMutex">TryMutex</link> requirements,
|
|
and an object <code>b</code> of type <code>bool</code>,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>ScopedTryLock Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>L lk(m);</code></entry>
|
|
<entry>Constructs an object <code>lk</code>, and associates mutex
|
|
object <code>m</code> with it, then calls
|
|
<code>try_lock()</code></entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>L lk(m,b);</code></entry>
|
|
<entry>Constructs an object <code>lk</code>, and associates mutex
|
|
object <code>m</code> with it, then if <code>b</code>, calls
|
|
<code>lock()</code></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.TimedLock">
|
|
<title>TimedLock Concept</title>
|
|
|
|
<para>A TimedLock is a refinement of <link
|
|
linkend="threads.concepts.TryLock">TryLock</link>.
|
|
For a TimedLock type <code>L</code>
|
|
and an object <code>lk</code> of that type,
|
|
and an object <code>t</code> of type <classname>boost::xtime</classname>,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>TimedLock Expressions</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>lk.timed_lock(t)</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if locked().</para>
|
|
|
|
<para>Makes a blocking attempt
|
|
to lock the associated mutex object, and returns <code>true</code>
|
|
if successful within the specified time <code>t</code>, otherwise
|
|
<code>false</code>. If the associated mutex object is already
|
|
locked by the same thread the behavior is dependent on the <link
|
|
linkend="threads.concepts.locking-strategies">locking
|
|
strategy</link> of the associated mutex object.</para>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.ScopedTimedLock">
|
|
<title>ScopedTimedLock Concept</title>
|
|
|
|
<para>A ScopedTimedLock is a refinement of <link
|
|
linkend="threads.concepts.TimedLock">TimedLock</link>.
|
|
For a ScopedTimedLock type <code>L</code>
|
|
and an object <code>lk</code> of that type,
|
|
and an object <code>m</code> of a type meeting the
|
|
<link linkend="threads.concepts.TimedMutex">TimedMutex</link> requirements,
|
|
and an object <code>b</code> of type <code>bool</code>,
|
|
and an object <code>t</code> of type <classname>boost::xtime</classname>,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>ScopedTimedLock Expressions</title>
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>L lk(m,t);</code></entry>
|
|
<entry>Constructs an object <code>lk</code>, and associates mutex
|
|
object <code>m</code> with it, then calls
|
|
<code>timed_lock(t)</code></entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>L lk(m,b);</code></entry>
|
|
<entry>Constructs an object <code>lk</code>, and associates mutex
|
|
object <code>m</code> with it, then if <code>b</code>, calls
|
|
<code>lock()</code></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="threads.concepts.lock-models">
|
|
<title>Lock Models</title>
|
|
|
|
<para>&Boost.Threads; currently supplies twelve models of
|
|
<link linkend="threads.concepts.Lock">Lock</link>
|
|
and its refinements.</para>
|
|
|
|
<table>
|
|
<title>Lock Models</title>
|
|
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Concept</entry>
|
|
<entry>Refines</entry>
|
|
<entry>Models</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.Lock">Lock</link></entry>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
|
|
<entry><link linkend="threads.concepts.Lock">Lock</link></entry>
|
|
<entry>
|
|
<para><classname>boost::mutex::scoped_lock</classname></para>
|
|
<para><classname>boost::recursive_mutex::scoped_lock</classname></para>
|
|
|
|
<para><classname>boost::try_mutex::scoped_lock</classname></para>
|
|
<para><classname>boost::recursive_try_mutex::scoped_lock</classname></para>
|
|
|
|
<para><classname>boost::timed_mutex::scoped_lock</classname></para>
|
|
<para><classname>boost::recursive_timed_mutex::scoped_lock</classname></para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.TryLock">TryLock</link></entry>
|
|
<entry><link linkend="threads.concepts.Lock">Lock</link></entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link></entry>
|
|
<entry><link linkend="threads.concepts.TryLock">TryLock</link></entry>
|
|
<entry>
|
|
<para><classname>boost::try_mutex::scoped_try_lock</classname></para>
|
|
<para><classname>boost::recursive_try_mutex::scoped_try_lock</classname></para>
|
|
|
|
<para><classname>boost::timed_mutex::scoped_try_lock</classname></para>
|
|
<para><classname>boost::recursive_timed_mutex::scoped_try_lock</classname></para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.TimedLock">TimedLock</link></entry>
|
|
<entry><link linkend="threads.concepts.TryLock">TryLock</link></entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.ScopedTimedLock">ScopedTimedLock</link></entry>
|
|
<entry><link linkend="threads.concepts.TimedLock">TimedLock</link></entry>
|
|
<entry>
|
|
<para><classname>boost::timed_mutex::scoped_timed_lock</classname></para>
|
|
<para><classname>boost::recursive_timed_mutex::scoped_timed_lock</classname></para>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-mutexes">
|
|
<title>Read/Write Mutexes</title>
|
|
<note>Since the read/write mutex and related classes are new,
|
|
both interface and implementation are liable to change
|
|
in future releases of &Boost.Threads;.
|
|
The lock concepts and lock promotion and demotion in particular
|
|
are still under discussion and very likely to change.</note>
|
|
|
|
<para>A read/write mutex (short for reader/writer mutual-exclusion) object
|
|
is used to serialize access to a resource shared between multiple
|
|
threads, where multiple "readers" can share simultaneous access, but
|
|
"writers" require exclusive access. The
|
|
<link linkend="threads.concepts.ReadWriteMutex">ReadWriteMutex</link> concept, with
|
|
<link linkend="threads.concepts.TryReadWriteMutex">TryReadWriteMutex</link> and
|
|
<link linkend="threads.concepts.TimedReadWriteMutex"> TimedReadWriteMutex</link>
|
|
refinements formalize the requirements. A model that implements
|
|
ReadWriteMutex and its refinements has three states:
|
|
<emphasis role="bold">read-locked</emphasis>,
|
|
<emphasis role="bold">write-locked</emphasis>, and
|
|
<emphasis role="bold">unlocked</emphasis>.
|
|
Before reading from a shared resource, a thread
|
|
<emphasis role="bold">read-locks</emphasis>
|
|
a &Boost.Threads; read/write mutex object
|
|
(an object whose type is a model of
|
|
<link linkend="threads.concepts.ReadWriteMutex">ReadWriteMutex</link>
|
|
or one of it's refinements), ensuring
|
|
<link linkend="threads.glossary.thread-safe">thread-safe</link>
|
|
access for reading from the shared resource. Before writing
|
|
to a shared resource, a thread
|
|
<emphasis role="bold">write-locks</emphasis> a &Boost.Threads;
|
|
read/write mutex object
|
|
(an object whose type is a model of
|
|
<link linkend="threads.concepts.ReadWriteMutex">ReadWriteMutex</link>
|
|
or one of it's refinements), ensuring
|
|
<link linkend="threads.glossary.thread-safe">thread-safe</link>
|
|
access for altering the shared resource. When use of the shared
|
|
resource is complete, the thread unlocks the mutex object,
|
|
allowing another thread to acquire the lock and use the shared
|
|
resource.</para>
|
|
|
|
<para>Traditional C thread APIs that provide read/write mutex
|
|
primitives (like POSIX threads) expose functions to lock and unlock a
|
|
mutex object. This is dangerous since it's easy to forget to unlock a
|
|
locked mutex. When the flow of control is complex, with multiple
|
|
return points, the likelihood of forgetting to unlock a mutex object
|
|
becomes even greater. When exceptions are thrown, it becomes nearly
|
|
impossible to ensure that the mutex object is unlocked
|
|
properly when using these traditional API's. The result is
|
|
<link linkend="threads.glossary.deadlock">deadlock</link>.</para>
|
|
|
|
<para>Many C++ threading libraries use a pattern known as <emphasis>Scoped
|
|
Locking</emphasis> &cite.SchmidtStalRohnertBuschmann; to free the
|
|
programmer from the need to explicitly lock and unlock
|
|
read/write mutex objects. With this pattern, a
|
|
<link linkend="threads.concepts.read-write-lock-concepts">Read/Write Lock</link>
|
|
concept is employed where the lock object's constructor locks
|
|
the associated read/write mutex object
|
|
and the destructor automatically does the unlocking. The
|
|
&Boost.Threads; library takes this pattern to
|
|
the extreme in that
|
|
<link linkend="threads.concepts.read-write-lock-concepts">Read/Write Lock</link>
|
|
concepts are the only way to lock and unlock a read/write mutex
|
|
object: lock and unlock functions are not exposed by any
|
|
&Boost.Threads; read/write mutex objects. This helps to
|
|
ensure safe usage patterns, especially when code throws exceptions.</para>
|
|
|
|
<section id="threads.concepts.read-write-locking-strategies">
|
|
<title>Locking Strategies</title>
|
|
|
|
<para>Every read/write mutex object 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
|
|
read/write mutex object.</para>
|
|
|
|
<section id="threads.concepts.read-write-locking-strategies.recursive">
|
|
<title>Recursive Locking Strategy</title>
|
|
|
|
<para>With a recursive locking strategy, when a thread attempts
|
|
to acquire a lock on a read/write mutex object
|
|
for which it already owns a lock, the operation is successful,
|
|
except in the case where a thread holding a read-lock
|
|
attempts to obtain a write lock, in which case a
|
|
<classname>boost::lock_error</classname> exception will
|
|
be thrown. Note the distinction between a thread, which may have
|
|
multiple locks outstanding on a recursive read/write mutex object,
|
|
and a lock object, which even for a recursive read/write mutex
|
|
object cannot have any of its lock functions called multiple
|
|
times without first calling unlock.</para>
|
|
|
|
<informaltable>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Lock Type Held</entry>
|
|
<entry>Lock Type Requested</entry>
|
|
<entry>Action</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>read-lock</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Grant the read-lock immediately</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-lock</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>If this thread is the only holder of the read-lock,
|
|
grants the write lock immediately. Otherwise throws a
|
|
<classname>boost::lock_error</classname> exception.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Grants the (additional) read-lock immediately.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry> Grant the write-lock immediately</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
|
|
<para>Internally a lock count is maintained and the owning
|
|
thread must unlock the mutex object the same number of times
|
|
that it locked it before the mutex object's state returns
|
|
to unlocked. Since mutex objects in &Boost.Threads; expose
|
|
locking functionality only through lock concepts, a thread
|
|
will always unlock a mutex object the same number of times
|
|
that it locked it. This helps to eliminate a whole set of
|
|
errors typically found in traditional C style thread APIs.
|
|
</para>
|
|
|
|
<para>&Boost.Threads; does not currently provide any read/write mutex objects
|
|
that use this strategy. A successful implementation of this locking strategy
|
|
may require
|
|
<link linkend="threads.concepts.read-write-locking-strategies.thread-identification">thread identification</link>.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-locking-strategies.checked">
|
|
<title>Checked Locking Strategy</title>
|
|
|
|
<para>With a checked locking strategy, when a thread attempts
|
|
to acquire a lock on the mutex object for which the thread
|
|
already owns a lock, the operation will fail with some sort of
|
|
error indication, except in the case of multiple read-lock
|
|
acquisition which is a normal operation for ANY ReadWriteMutex.
|
|
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 &Boost.Threads;, an exception of type
|
|
<classname>boost::lock_error</classname> would be thrown in
|
|
these cases.</para>
|
|
|
|
<informaltable>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Lock Type Held</entry>
|
|
<entry>Lock Type Requested</entry>
|
|
<entry>Action</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>read-lock</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Grant the read-lock immediately</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-lock</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>Throw <classname>boost::lock_error</classname></entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Throw <classname>boost::lock_error</classname></entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry> Throw <classname>boost::lock_error</classname></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
|
|
<para>&Boost.Threads; does not currently provide any read/write mutex objects
|
|
that use this strategy. A successful implementation of this locking strategy
|
|
may require
|
|
<link linkend="threads.concepts.read-write-locking-strategies.thread-identification">thread identification</link>.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-locking-strategies.unchecked">
|
|
<title>Unchecked Locking Strategy</title>
|
|
|
|
<para>With an unchecked locking strategy, when a thread
|
|
attempts to acquire a lock on the read/write mutex object
|
|
for which the thread already owns a lock, the operation
|
|
will <link linkend="threads.glossary.deadlock">deadlock</link>.
|
|
In general this locking strategy is less safe than a checked
|
|
or recursive strategy, but it can be a faster strategy and so
|
|
is employed by many libraries.</para>
|
|
|
|
<informaltable>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Lock Type Held</entry>
|
|
<entry>Lock Type Requested</entry>
|
|
<entry>Action</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>read-lock</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Grant the read-lock immediately</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-lock</entry>
|
|
<entry>write-lock</entry>
|
|
<entry><link linkend="threads.glossary.deadlock">Deadlock</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry><link linkend="threads.glossary.deadlock">Deadlock</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry><link linkend="threads.glossary.deadlock">Deadlock</link></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
|
|
<para>&Boost.Threads; does not currently provide any mutex
|
|
objects that use this strategy. For ReadWriteMutexes on
|
|
platforms that contain natively recursive synchronization
|
|
primitives, implementing a guaranteed-deadlock can actually
|
|
involve extra work, and would likely require
|
|
<link linkend="threads.concepts.read-write-locking-strategies.thread-identification">thread identification</link>.
|
|
</para>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-locking-strategies.unspecified">
|
|
<title>Unspecified Locking Strategy</title>
|
|
|
|
<para>With an unspecified locking strategy, when a thread
|
|
attempts to acquire a lock on a read/write mutex object for
|
|
which the thread already owns a lock, the operation results
|
|
in <link linkend="threads.glossary.undefined-behavior">undefined behavior</link>.
|
|
When a read/write mutex object has an unspecified locking
|
|
strategy the programmer must assume that the read/write mutex
|
|
object instead uses an unchecked strategy as the worse case,
|
|
although some platforms may exhibit a mix of unchecked and
|
|
recursive behavior.</para>
|
|
|
|
<informaltable>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Lock Type Held</entry>
|
|
<entry>Lock Type Requested</entry>
|
|
<entry>Action</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>read-lock</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Grant the read-lock immediately</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-lock</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>
|
|
<link linkend="threads.glossary.undefined-behavior">Undefined</link>, but generally <link linkend="threads.glossary.deadlock">deadlock</link>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry><link linkend="threads.glossary.undefined-behavior">Undefined</link>, but generally <link linkend="threads.glossary.deadlock">deadlock</link></entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry><link linkend="threads.glossary.undefined-behavior">Undefined</link>, but generally <link linkend="threads.glossary.deadlock">deadlock</link></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
|
|
<para>In general a read/write mutex object with an unspecified
|
|
locking strategy is unsafe, and it requires programmer discipline
|
|
to use the read/write mutex object 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
|
|
classes
|
|
<classname>read_write_mutex</classname>,
|
|
<classname>try_read_write_mutex</classname>, and
|
|
<classname>timed_read_write_mutex</classname>
|
|
use this locking strategy despite the lack of safety.</para>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-locking-strategies.thread-identification">
|
|
<title>Thread Identification</title>
|
|
|
|
<para>ReadWriteMutexes can support specific Locking Strategies
|
|
(recursive and checked) which help to detect and protect against
|
|
self-deadlock. Self-deadlock can occur when a holder of a locked
|
|
ReadWriteMutex attempts to obtain another lock. Given an
|
|
implemention <emphasis>I</emphasis> which is susceptible to
|
|
self-deadlock but otherwise correct and efficient, a recursive or
|
|
checked implementation <emphasis>Ir</emphasis> or
|
|
<emphasis>Ic</emphasis> can use the same basic implementation,
|
|
but make special checks against self-deadlock by tracking the
|
|
identities of thread(s) currently holding locks. This approach
|
|
makes deadlock detection othrogonal to the basic ReadWriteMutex
|
|
implementaion.</para>
|
|
|
|
<para>Alternatively, a different basic implementation for
|
|
ReadWriteMutex concepts,
|
|
<emphasis>I'</emphasis> (I-Prime) may exist which uses recursive
|
|
or checked versions of synchronization primitives to produce
|
|
a recursive or checked ReadWriteMutex while still providing
|
|
flexibility in terms of Scheduling Policies. </para>
|
|
|
|
<para>Please refer to the &Boost.Threads;
|
|
<link linkend="threads.concepts.read-write-mutex-concepts">read/write mutex concept</link>
|
|
documentation for a discussion of locking strategies.
|
|
The read/write mutex supports only the
|
|
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">unspecified</link>
|
|
locking strategy. ReadWriteMutexes are parameterized on a
|
|
Mutex type which they use to control write-locking
|
|
and access to internal state.</para>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-locking-strategies.promotion">
|
|
<title>Lock Promotion</title>
|
|
|
|
<para>ReadWriteMutexes can support lock promotion, where a
|
|
mutex which is in the read-locked state transitions to a
|
|
write-locked state without releasing the lock. Lock
|
|
promotion can be tricky to implement; for instance,
|
|
extra care must be taken to ensure that only one thread holding a
|
|
read-lock can block awaiting promotion at any given time. If
|
|
more than one read-lock holder is allowed to enter a blocked
|
|
state while waiting to be promoted, deadlock will result since
|
|
both threads will be waiting for the other to release their read-lock.
|
|
</para>
|
|
|
|
<para>Currently, &Boost.Threads; supports lock promotion
|
|
through <code>promote()</code>, <code>try_promote()</code>,
|
|
and <code>timed_promote()</code> operations.</para>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-locking-strategies.demotion">
|
|
<title>Lock Demotion</title>
|
|
|
|
<para>ReadWriteMutexes can support lock demotion, where a
|
|
mutex which is in the write-locked state transitions to a
|
|
read-locked state without releasing the lock.
|
|
Since by definition only one thread at a time may hold
|
|
a write-lock, the problem with deadlock that can occur
|
|
during lock promotion is not a problem for lock
|
|
demotion.</para>
|
|
|
|
<para>Currently, &Boost.Threads; supports lock demotion
|
|
through <code>demote()</code>, <code>try_demote()</code>,
|
|
and <code>timed_demote()</code> operations.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-scheduling-policies">
|
|
<title>Scheduling Policies</title>
|
|
|
|
<para>Every read/write mutex object follows one of several scheduling
|
|
policies. These policies define the semantics when the mutex object
|
|
is unlocked and there is more than one thread waiting to acquire a
|
|
lock. In other words, the policy defines which waiting thread shall
|
|
acquire the lock. For a read/write mutex, it is particularly important
|
|
to define the behavior when threads are requesting both read and
|
|
write access simultaneously. This will be referred to as "inter-class
|
|
scheduling" because it describes the scheduling between two
|
|
classes of threads (those waiting for a read lock and those
|
|
waiting for a write lock).</para>
|
|
|
|
<para>For some types of inter-class scheduling, an "intra-class"
|
|
scheduling policy can also be defined that will describe the order
|
|
in which waiting threads of the same class (i.e., those
|
|
waiting for the same type of lock) will acquire the thread.
|
|
</para>
|
|
|
|
<section id="threads.concepts.read-write-scheduling-policies.inter-class">
|
|
<title>Inter-Class Scheduling Policies</title>
|
|
|
|
<section id="threads.concepts.read-write-scheduling-policies.reader-priority">
|
|
<title>ReaderPriority</title>
|
|
|
|
<para>With ReaderPriority scheduling, any pending request for
|
|
a read-lock will have priority over a pending request for a
|
|
write-lock, irrespective of the current lock state of the
|
|
read/write mutex, and irrespective of the relative order
|
|
that the pending requests arrive.</para>
|
|
|
|
<informaltable>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Current mutex state</entry>
|
|
<entry>Request Type</entry>
|
|
<entry>Action</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>unlocked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Grant the read-lock immediately</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-locked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Grant the additional read-lock immediately.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Wait to acquire the lock until the thread
|
|
holding the write-lock releases its lock (or until
|
|
the specified time, if any). A
|
|
read-lock will be granted to all pending readers
|
|
before any other thread can acquire a write-lock.
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>unlocked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>Grant the write-lock immediately, if and
|
|
only if there are no pending read-lock requests.
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-locked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry> Wait to acquire the lock until all
|
|
threads holding read-locks release their locks
|
|
<emphasis role="bold">AND</emphasis> no requests
|
|
for read-locks exist. If other write-lock
|
|
requests exist, the lock is granted in accordance
|
|
with the intra-class scheduling policy.
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>Wait to acquire the lock until the thread
|
|
holding the write-lock releases its lock
|
|
<emphasis role="bold">AND</emphasis> no requests
|
|
for read-locks exist. If other write-lock
|
|
requests exist, the lock is granted in accordance
|
|
with the intra-class scheduling policy.
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-locked</entry>
|
|
<entry>promote</entry>
|
|
<entry><para>TODO</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>demote</entry>
|
|
<entry><para>TODO</para></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-scheduling-policies.writer-priority">
|
|
<title>WriterPriority</title>
|
|
|
|
<para>With WriterPriority scheduling, any pending request
|
|
for a write-lock will have priority over a pending request
|
|
for a read-lock, irrespective of the current lock state
|
|
of the read/write mutex, and irrespective of the relative
|
|
order that the pending requests arrive.</para>
|
|
|
|
<informaltable>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Current mutex state</entry>
|
|
<entry>Request Type</entry>
|
|
<entry>Action</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>unlocked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Grant the read-lock immediately.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-locked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Grant the additional read-lock immediately,
|
|
<emphasis role="bold">IF</emphasis> no outstanding
|
|
requests for a write-lock exist; otherwise TODO.
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry> Wait to acquire the lock until the
|
|
thread holding the write-lock
|
|
releases its lock. The read lock will be granted
|
|
once no other outstanding write-lock requests
|
|
exist.
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>unlocked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>Grant the write-lock immediately.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-locked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>Wait to acquire the lock until all
|
|
threads holding read-locks release their locks.
|
|
If other write-lock requests exist, the lock
|
|
is granted in accordance with the intra-class
|
|
scheduling policy. This request will be granted
|
|
before any new read-lock requests are granted.
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>Wait to acquire the lock until the thread
|
|
holding the write-lock releases its lock. If
|
|
other write-lock requests exist, the lock is
|
|
granted in accordance with the intra-class
|
|
scheduling policy. This request will be granted
|
|
before any new read-lock requests are granted.
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-locked</entry>
|
|
<entry>promote</entry>
|
|
<entry><para>TODO</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>demote</entry>
|
|
<entry><para>TODO</para></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-scheduling-policies.alternating-many-reads">
|
|
<title>AlternatingPriority/ManyReads</title>
|
|
|
|
<para>With AlternatingPriority/ManyReads scheduling, reader
|
|
or writer starvation is avoided by alternatively granting read
|
|
or write access when pending requests exist for both types of
|
|
locks. Outstanding read-lock requests are treated as a group
|
|
when it is the "readers' turn"</para>
|
|
|
|
<informaltable>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Current mutex state</entry>
|
|
<entry>Request Type</entry>
|
|
<entry>Action</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>unlocked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Grant the read-lock immediately.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-locked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Grant the additional read-lock immediately,
|
|
<emphasis role="bold">IF</emphasis> no outstanding
|
|
requests for a write-lock exist. If outstanding
|
|
write-lock requests exist, this lock will not
|
|
be granted until at least one of the
|
|
write-locks is granted and released. If other
|
|
read-lock requests exist, all read-locks will be
|
|
granted as a group.
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry> Wait to acquire the lock until the thread
|
|
holding the write-lock releases its lock. If other
|
|
outstanding write-lock requests exist, they will
|
|
have to wait until all current read-lock requests
|
|
are serviced.
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>unlocked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>Grant the write-lock immediately.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-locked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>
|
|
<para>Wait to acquire the lock until all threads
|
|
holding read-locks release their locks.</para>
|
|
|
|
<para>If other write-lock requests exist, this
|
|
lock will be granted to one of them in accordance
|
|
with the intra-class scheduling policy.</para>
|
|
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>Wait to acquire the lock until the thread
|
|
holding the write-lock releases its lock. If
|
|
other outstanding read-lock requests exist, this
|
|
lock will not be granted until all of the
|
|
currently waiting read-locks are granted and
|
|
released. If other write-lock requests exist,
|
|
this lock will be granted in accordance with the
|
|
intra-class scheduling policy.
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-locked</entry>
|
|
<entry>promote</entry>
|
|
<entry><para>TODO</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>demote</entry>
|
|
<entry><para>TODO</para></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-scheduling-policies.alternating-single-read">
|
|
<title>AlternatingPriority/SingleRead</title>
|
|
|
|
<para>With AlternatingPriority/SingleRead scheduling, reader
|
|
or writer starvation is avoided by alternatively granting read
|
|
or write access when pending requests exist for both types of
|
|
locks. Outstanding read-lock requests are services one at a
|
|
time when it is the "readers' turn"</para>
|
|
|
|
<informaltable>
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Current mutex state</entry>
|
|
<entry>Request Type</entry>
|
|
<entry>Action</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>unlocked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Grant the read-lock immediately.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-locked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>Grant the additional read-lock immediately,
|
|
<emphasis role="bold">IF</emphasis> no outstanding
|
|
requests for a write-lock exist. If outstanding
|
|
write-lock requests exist, this lock will not
|
|
be granted until at least one of the write-locks
|
|
is granted and released.
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>read-lock</entry>
|
|
<entry>
|
|
<para>Wait to acquire the lock until the thread
|
|
holding the write-lock releases its lock.</para>
|
|
<para>If other outstanding write-lock requests
|
|
exist, exactly one read-lock request will be
|
|
granted before the next write-lock is granted.
|
|
</para>
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>unlocked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>Grant the write-lock immediately.</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-locked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>
|
|
<para>Wait to acquire the lock until all
|
|
threads holding read-locks release their
|
|
locks.</para>
|
|
|
|
<para>If other write-lock requests exist,
|
|
this lock will be granted to one of them
|
|
in accordance with the intra-class
|
|
scheduling policy.</para></entry>
|
|
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>write-lock</entry>
|
|
<entry>Wait to acquire the lock until the
|
|
thread holding the write-lock releases its
|
|
lock. If other outstanding read-lock requests
|
|
exist, this lock can not be granted until
|
|
exactly one read-lock request is granted and
|
|
released. If other write-lock requests exist,
|
|
this lock will be granted in accordance with
|
|
the intra-class scheduling policy.
|
|
<para>TODO: try-lock, timed-lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>read-locked</entry>
|
|
<entry>promote</entry>
|
|
<entry><para>TODO</para></entry>
|
|
</row>
|
|
<row>
|
|
<entry>write-locked</entry>
|
|
<entry>demote</entry>
|
|
<entry><para>TODO</para></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</informaltable>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-scheduling-policies.intra-class">
|
|
<title>Intra-Class Scheduling Policies</title>
|
|
|
|
<para>Please refer to
|
|
<xref linkend="threads.concepts.sheduling-policies" />
|
|
for a discussion of mutex scheduling policies, which are identical to
|
|
read/write mutex intra-class scheduling policies.</para>
|
|
|
|
<para>For threads waiting to obtain write-locks, the read/write mutex
|
|
supports only the
|
|
<link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>
|
|
intra-class scheduling policy. That is, given a set of threads
|
|
waiting for write-locks, the order, relative to one another, in
|
|
which they receive the write-lock is unspecified.</para>
|
|
|
|
<para>For threads waiting to obtain read-locks, the read/write mutex
|
|
supports only the
|
|
<link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>
|
|
intra-class scheduling policy. That is, given a set of threads
|
|
waiting for read-locks, the order, relative to one another, in
|
|
which they receive the read-lock is unspecified.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-mutex-concepts">
|
|
<title>Mutex Concepts</title>
|
|
|
|
<section id="threads.concepts.ReadWriteMutex">
|
|
<title>ReadWriteMutex Concept</title>
|
|
|
|
<para>A ReadWriteMutex object has three states: read-locked,
|
|
write-locked, and unlocked. ReadWriteMutex object state can
|
|
only be determined by a lock object meeting the appropriate lock concept
|
|
requirements and constructed for the ReadWriteMutex object.</para>
|
|
|
|
<para>A ReadWriteMutex is
|
|
<ulink url="../../libs/utility/utility.htm#Class%20noncopyable">NonCopyable</ulink>.
|
|
</para>
|
|
|
|
<para>For a ReadWriteMutex type <code>M</code>,
|
|
and an object <code>m</code> of that type,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>ReadWriteMutex Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>M m;</code></entry>
|
|
<entry>Constructs a read/write mutex object <code>m</code>.
|
|
Post-condition: <code>m</code> is unlocked.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>(&m)->~M();</code></entry>
|
|
<entry>Precondition: <code>m</code> is unlocked.
|
|
Destroys a read/write mutex object <code>m</code>.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>M::scoped_read_write_lock</code></entry>
|
|
<entry>A type meeting the
|
|
<link linkend="threads.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link>
|
|
requirements. </entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>M::scoped_read_lock</code></entry>
|
|
<entry>A type meeting the
|
|
<link linkend="threads.concepts.ScopedLock">ScopedLock</link>
|
|
requirements. </entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>M::scoped_write_lock</code></entry>
|
|
<entry>A type meeting the
|
|
<link linkend="threads.concepts.ScopedLock">ScopedLock</link>
|
|
requirements. </entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.TryReadWriteMutex">
|
|
<title>TryReadWriteMutex Concept</title>
|
|
|
|
<para>A TryReadWriteMutex is a refinement of
|
|
<link linkend="threads.concepts.ReadWriteMutex">ReadWriteMutex</link>.
|
|
For a TryReadWriteMutex type <code>M</code>
|
|
and an object <code>m</code> of that type,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>TryReadWriteMutex Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>M::scoped_try_read_write_lock</code></entry>
|
|
<entry>A type meeting the
|
|
<link linkend="threads.concepts.ScopedTryReadWriteLock">ScopedTryReadWriteLock</link>
|
|
requirements.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>M::scoped_try_read_lock</code></entry>
|
|
<entry>A type meeting the
|
|
<link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link>
|
|
requirements.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>M::scoped_try_write_lock</code></entry>
|
|
<entry>A type meeting the
|
|
<link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link>
|
|
requirements.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.TimedReadWriteMutex">
|
|
<title>TimedReadWriteMutex Concept</title>
|
|
|
|
<para>A TimedReadWriteMutex is a refinement of
|
|
<link linkend="threads.concepts.TryReadWriteMutex">TryReadWriteMutex</link>.
|
|
For a TimedReadWriteMutex type <code>M</code>
|
|
and an object <code>m</code> of that type
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>TimedReadWriteMutex Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>M::scoped_timed_read_write_lock</code></entry>
|
|
<entry>A type meeting the
|
|
<link linkend="threads.concepts.ScopedTimedReadWriteLock">ScopedTimedReadWriteLock</link>
|
|
requirements.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>M::scoped_timed_read_lock</code></entry>
|
|
<entry>A type meeting the
|
|
<link linkend="threads.concepts.ScopedTimedLock">ScopedTimedLock</link>
|
|
requirements.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>M::scoped_timed_write_lock</code></entry>
|
|
<entry>A type meeting the
|
|
<link linkend="threads.concepts.ScopedTimedLock">ScopedTimedLock</link>
|
|
requirements.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-mutex-models">
|
|
<title>Mutex Models</title>
|
|
|
|
<para>&Boost.Threads; currently supplies three models of
|
|
<link linkend="threads.concepts.ReadWriteMutex">ReadWriteMutex</link>
|
|
and its refinements.</para>
|
|
|
|
<table>
|
|
<title>Mutex Models</title>
|
|
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Concept</entry>
|
|
<entry>Refines</entry>
|
|
<entry>Models</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.ReadWriteMutex">ReadWriteMutex</link></entry>
|
|
<entry></entry>
|
|
<entry><classname>boost::read_write_mutex</classname></entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.TryReadWriteMutex">TryReadWriteMutex</link></entry>
|
|
<entry><link linkend="threads.concepts.ReadWriteMutex">ReadWriteMutex</link></entry>
|
|
<entry><classname>boost::try_read_write_mutex</classname></entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.TimedReadWriteMutex">TimedReadWriteMutex</link></entry>
|
|
<entry><link linkend="threads.concepts.TryReadWriteMutex">TryReadWriteMutex</link></entry>
|
|
<entry><classname>boost::timed_read_write_mutex</classname></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-lock-concepts">
|
|
<title>Lock Concepts</title>
|
|
|
|
<para>A read/write lock object provides a safe means for locking
|
|
and unlocking a read/write mutex object (an object whose type is
|
|
a model of
|
|
<link linkend="threads.concepts.ReadWriteMutex">ReadWriteMutex</link>
|
|
or one of its refinements). In other words they are an
|
|
implementation of the <emphasis>Scoped Locking</emphasis>
|
|
&cite.SchmidtStalRohnertBuschmann; pattern. The
|
|
<link linkend="threads.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link>,
|
|
<link linkend="threads.concepts.ScopedTryReadWriteLock">ScopedTryReadWriteLock</link>, and
|
|
<link linkend="threads.concepts.ScopedTimedReadWriteLock">ScopedTimedReadWriteLock</link>
|
|
concepts formalize the requirements.</para>
|
|
|
|
<para>Read/write lock objects are constructed with a reference to a
|
|
read/write mutex object and typically acquire ownership of the
|
|
read/write mutex object by setting its state to locked. They also
|
|
ensure ownership is relinquished in the destructor. Lock objects
|
|
also expose functions to query the lock status and to manually lock
|
|
and unlock the read/write mutex object.</para>
|
|
|
|
<para>Read/write lock objects are meant to be short lived, expected
|
|
to be used at block scope only. The read/write lock objects are not
|
|
<link linkend="threads.glossary.thread-safe">thread-safe</link>.
|
|
Read/write lock objects must maintain state to indicate whether or
|
|
not they've been locked and this state is not protected by any
|
|
synchronization concepts. For this reason a read/write lock object
|
|
should never be shared between multiple threads.</para>
|
|
|
|
<section id="threads.concepts.ReadWriteLock">
|
|
<title>ReadWriteLock Concept</title>
|
|
|
|
<para>For a read/write lock type <code>L</code>
|
|
and an object <code>lk</code>
|
|
and const object <code>clk</code> of that type,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>ReadWriteLock Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>(&lk)->~L();</code></entry>
|
|
<entry><code>if (locked()) unlock();</code></entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>(&clk)->operator const void*()</code></entry>
|
|
<entry>Returns type void*, non-zero if the associated read/write
|
|
mutex object has been either read-locked or write-locked by
|
|
<code>clk</code>, otherwise 0.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>clk.locked()</code></entry>
|
|
<entry>Returns a <code>bool</code>, <code>(&clk)->operator
|
|
const void*() != 0</code></entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>clk.state()</code></entry>
|
|
<entry>Returns an enumeration constant of type <code>read_write_lock_state</code>:
|
|
<code>read_write_lock_state::read_locked</code> if the associated read/write mutex object has been
|
|
read-locked by <code>clk</code>, <code>read_write_lock_state::write_locked</code> if it
|
|
has been write-locked by <code>clk</code>, and <code>read_write_lock_state::unlocked</code>
|
|
if has not been locked by <code>clk</code>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>clk.read_locked()</code></entry>
|
|
<entry>Returns a <code>bool</code>, <code>(&clk)->state() == read_write_lock_state::read_locked</code>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>clk.write_locked()</code></entry>
|
|
<entry>Returns a <code>bool</code>, <code>(&clk)->state() == read_write_lock_state::write_locked</code>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>lk.read_lock()</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if <code>locked()</code>.</para>
|
|
|
|
<para>If the associated read/write mutex
|
|
object is already read-locked by some other
|
|
thread, the effect depends on the
|
|
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class scheduling policy</link>
|
|
of the associated read/write mutex:
|
|
either immediately obtains an additional
|
|
read-lock on the associated read/write
|
|
mutex, or places the current thread in the
|
|
<link linkend="threads.glossary.thread-state">Blocked</link>
|
|
state until the associated read/write mutex
|
|
is unlocked, after which the current thread
|
|
is placed in the
|
|
<link linkend="threads.glossary.thread-state">Ready</link>
|
|
state, eventually to be returned to the
|
|
<link linkend="threads.glossary.thread-state">Running</link>
|
|
state.</para>
|
|
|
|
<para>If the associated read/write mutex
|
|
object is already write-locked by some other
|
|
thread, places the current thread in the
|
|
<link linkend="threads.glossary.thread-state">Blocked</link>
|
|
state until the associated read/write mutex
|
|
is unlocked, after which the current thread
|
|
is placed in the
|
|
<link linkend="threads.glossary.thread-state">Ready</link>
|
|
state, eventually to be returned to the
|
|
<link linkend="threads.glossary.thread-state">Running</link>
|
|
state.</para>
|
|
|
|
<para>If the associated read/write mutex
|
|
object is already locked by the same thread
|
|
the behavior is dependent on the
|
|
<link linkend="threads.concepts.read-write-locking-strategies">locking strategy</link>
|
|
of the associated read/write mutex object.
|
|
</para>
|
|
|
|
<para>Postcondition: <code>state() == read_write_lock_state::read_locked</code></para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>lk.write_lock()</code></entry>
|
|
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if <code>locked()</code>.</para>
|
|
|
|
<para>If the associated read/write mutex
|
|
object is already locked by some other
|
|
thread, places the current thread in the
|
|
<link linkend="threads.glossary.thread-state">Blocked</link>
|
|
state until the associated read/write mutex
|
|
is unlocked, after which the current thread
|
|
is placed in the
|
|
<link linkend="threads.glossary.thread-state">Ready</link>
|
|
state, eventually to be returned to the
|
|
<link linkend="threads.glossary.thread-state">Running</link>
|
|
state.</para>
|
|
|
|
<para>If the associated read/write mutex
|
|
object is already locked by the same thread
|
|
the behavior is dependent on the
|
|
<link linkend="threads.concepts.read-write-locking-strategies">locking strategy</link>
|
|
of the associated read/write mutex object.
|
|
</para>
|
|
|
|
<para>Postcondition: <code>state() == read_write_lock_state::write_locked</code></para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>lk.demote()</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if <code>state() != read_write_lock_state::write_locked</code>.</para>
|
|
|
|
<para>Converts the lock held on the associated read/write mutex
|
|
object from a write-lock to a read-lock without releasing
|
|
the lock.</para>
|
|
|
|
<para>Postcondition: <code>state() == read_write_lock_state::read_locked</code></para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>lk.promote()</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if <code>state() != read_write_lock_state::read_locked</code>
|
|
or if the lock cannot be promoted because another lock
|
|
on the same mutex is already waiting to be promoted.</para>
|
|
|
|
<para>Makes a blocking attempt to convert the lock held on the associated
|
|
read/write mutex object from a read-lock to a write-lock without releasing
|
|
the lock.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>lk.unlock()</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if <code>!locked()</code>.</para>
|
|
|
|
<para>Unlocks the associated read/write mutex.</para>
|
|
|
|
<para>Postcondition: <code>!locked()</code></para>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.ScopedReadWriteLock">
|
|
<title>ScopedReadWriteLock Concept</title>
|
|
|
|
<para>A ScopedReadWriteLock is a refinement of
|
|
<link linkend="threads.concepts.ReadWriteLock">ReadWriteLock</link>.
|
|
For a ScopedReadWriteLock type <code>L</code>
|
|
and an object <code>lk</code> of that type,
|
|
and an object <code>m</code> of a type meeting the
|
|
<link linkend="threads.concepts.ReadWriteMutex">ReadWriteMutex</link> requirements,
|
|
and an object <code>s</code> of type <code>read_write_lock_state</code>,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>ScopedReadWriteLock Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>L lk(m,s);</code></entry>
|
|
<entry>Constructs an object <code>lk</code> and associates read/write mutex
|
|
object <code>m</code> with it, then: if <code>s == read_write_lock_state::read_locked</code>, calls
|
|
<code>read_lock()</code>; if <code>s==read_write_lock_state::write_locked</code>,
|
|
calls <code>write_lock()</code>.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.TryReadWriteLock">
|
|
<title>TryReadWriteLock Expressions</title>
|
|
|
|
<para>A TryReadWriteLock is a refinement of
|
|
<link linkend="threads.concepts.ReadWriteLock">ReadWriteLock</link>.
|
|
For a TryReadWriteLock type <code>L</code>
|
|
and an object <code>lk</code> of that type,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>TryReadWriteLock Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>lk.try_read_lock()</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if locked().</para>
|
|
|
|
<para>Makes a non-blocking attempt to read-lock the associated read/write
|
|
mutex object, returning <code>true</code> if the attempt is successful,
|
|
otherwise <code>false</code>. If the associated read/write mutex object is
|
|
already locked by the same thread the behavior is dependent on the
|
|
<link linkend="threads.concepts.locking-strategies">locking
|
|
strategy</link> of the associated read/write mutex object.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>lk.try_write_lock()</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if locked().</para>
|
|
|
|
<para>Makes a non-blocking attempt to write-lock the associated read/write
|
|
mutex object, returning <code>true</code> if the attempt is successful,
|
|
otherwise <code>false</code>. If the associated read/write mutex object is
|
|
already locked by the same thread the behavior is dependent on the
|
|
<link linkend="threads.concepts.locking-strategies">locking
|
|
strategy</link> of the associated read/write mutex object.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>lk.try_demote()</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if <code>state() != read_write_lock_state::write_locked</code>.</para>
|
|
|
|
<para>Makes a non-blocking attempt to convert the lock held on the associated
|
|
read/write mutex object from a write-lock to a read-lock without releasing
|
|
the lock, returning <code>true</code> if the attempt is successful,
|
|
otherwise <code>false</code>.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>lk.try_promote()</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if <code>state() != read_write_lock_state::read_locked</code>.</para>
|
|
|
|
<para>Makes a non-blocking attempt to convert the lock held on the associated
|
|
read/write mutex object from a read-lock to a write-lock without releasing
|
|
the lock, returning <code>true</code> if the attempt is successful,
|
|
otherwise <code>false</code>.</para>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.ScopedTryReadWriteLock">
|
|
<title>ScopedTryReadWriteLock Expressions</title>
|
|
|
|
<para>A ScopedTryReadWriteLock is a refinement of
|
|
<link linkend="threads.concepts.TryReadWriteLock">TryReadWriteLock</link>.
|
|
For a ScopedTryReadWriteLock type <code>L</code>
|
|
and an object <code>lk</code> of that type,
|
|
and an object <code>m</code> of a type meeting the
|
|
<link linkend="threads.concepts.TryMutex">TryReadWriteMutex</link> requirements,
|
|
and an object <code>s</code> of type <code>read_write_lock_state</code>,
|
|
and an object <code>b</code> of type <code>blocking_mode</code>,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>ScopedTryReadWriteLock Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>L lk(m,s,b);</code></entry>
|
|
<entry>Constructs an object <code>lk</code> and associates read/write mutex
|
|
object <code>m</code> with it, then: if <code>s == read_write_lock_state::read_locked</code>, calls
|
|
<code>read_lock()</code> if <code>b</code>, otherwise <code>try_read_lock()</code>;
|
|
if <code>s==read_write_lock_state::write_locked</code>, calls <code>write_lock()</code> if <code>b</code>,
|
|
otherwise <code>try_write_lock</code>.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.TimedReadWriteLock">
|
|
<title>TimedReadWriteLock Concept</title>
|
|
|
|
<para>A TimedReadWriteLock is a refinement of
|
|
<link linkend="threads.concepts.TryReadWriteLock">TryReadWriteLock</link>.
|
|
For a TimedReadWriteLock type <code>L</code>
|
|
and an object <code>lk</code> of that type,
|
|
and an object <code>t</code> of type <classname>boost::xtime</classname>,
|
|
the following expressions must be well-formed
|
|
and have the indicated effects.</para>
|
|
|
|
<table>
|
|
<title>TimedReadWriteLock Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>lk.timed_read_lock(t)</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if locked().</para>
|
|
|
|
<para>Makes a blocking attempt to read-lock the associated read/write mutex object,
|
|
and returns <code>true</code> if successful within the specified time <code>t</code>,
|
|
otherwise <code>false</code>. If the associated read/write mutex object is already
|
|
locked by the same thread the behavior is dependent on the <link
|
|
linkend="threads.concepts.locking-strategies">locking
|
|
strategy</link> of the associated read/write mutex object.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>lk.timed_write_lock(t)</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if locked().</para>
|
|
|
|
<para>Makes a blocking attempt to write-lock the associated read/write mutex object,
|
|
and returns <code>true</code> if successful within the specified time <code>t</code>,
|
|
otherwise <code>false</code>. If the associated read/write mutex object is already
|
|
locked by the same thread the behavior is dependent on the <link
|
|
linkend="threads.concepts.locking-strategies">locking
|
|
strategy</link> of the associated read/write mutex object.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>lk.timed_demote(t)</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if <code>state() != read_write_lock_state::write_locked</code>.</para>
|
|
|
|
<para>Makes a blocking attempt to convert the lock held on the associated
|
|
read/write mutex object from a write-lock to a read-lock without releasing
|
|
the lock, returning <code>true</code> if the attempt is successful
|
|
in the specified time <code>t</code>, otherwise <code>false</code>.</para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>lk.timed_promote(t)</code></entry>
|
|
<entry>
|
|
<para>Throws <classname>boost::lock_error</classname>
|
|
if <code>state() != read_write_lock_state::read_locked</code>.</para>
|
|
|
|
<para>Makes a blocking attempt to convert the lock held on the associated
|
|
read/write mutex object from a read-lock to a write-lock without releasing
|
|
the lock, returning <code>true</code> if the attempt is successful
|
|
in the specified time <code>t</code>, otherwise <code>false</code>.</para>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="threads.concepts.ScopedTimedReadWriteLock">
|
|
<title>ScopedTimedReadWriteLock Concept</title>
|
|
|
|
<para>A ScopedTimedReadWriteLock is a refinement of
|
|
<link linkend="threads.concepts.TimedReadWriteLock">TimedReadWriteLock</link>.
|
|
For a ScopedTimedReadWriteLock type <code>L</code>
|
|
and an object <code>lk</code> of that type,
|
|
and an object <code>m</code> of a type meeting the
|
|
<link linkend="threads.concepts.TimedReadWriteMutex">TimedReadWriteMutex</link> requirements,
|
|
and an object <code>s</code> of type <code>read_write_lock_state</code>,
|
|
and an object <code>t</code> of type <classname>boost::xtime</classname>,
|
|
and an object <code>b</code> of type <code>blocking_mode</code>,
|
|
the following expressions must be well-formed and have the
|
|
indicated effects.</para>
|
|
|
|
<table>
|
|
<title>ScopedTimedReadWriteLock Expressions</title>
|
|
|
|
<tgroup cols="2">
|
|
<thead>
|
|
<row>
|
|
<entry>Expression</entry>
|
|
<entry>Effects</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><code>L lk(m,s,b);</code></entry>
|
|
<entry>Constructs an object <code>lk</code> and associates read/write mutex
|
|
object <code>m</code> with it, then: if <code>s == read_write_lock_state::read_locked</code>, calls
|
|
<code>read_lock()</code> if <code>b</code>, otherwise <code>try_read_lock()</code>;
|
|
if <code>s==read_write_lock_state::write_locked</code>, calls <code>write_lock()</code> if <code>b</code>,
|
|
otherwise <code>try_write_lock</code>.</entry>
|
|
</row>
|
|
<row>
|
|
<entry><code>L lk(m,s,t);</code></entry>
|
|
<entry>Constructs an object <code>lk</code> and associates read/write mutex
|
|
object <code>m</code> with it, then: if <code>s == read_write_lock_state::read_locked</code>, calls
|
|
<code>timed_read_lock(t)</code>; if <code>s==read_write_lock_state::write_locked</code>,
|
|
calls <code>timed_write_lock(t)</code>.</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="threads.concepts.read-write-lock-models">
|
|
<title>Lock Models</title>
|
|
|
|
<para>&Boost.Threads; currently supplies six models of
|
|
<link linkend="threads.concepts.ReadWriteLock">ReadWriteLock</link>
|
|
and its refinements.</para>
|
|
|
|
<table>
|
|
<title>Lock Models</title>
|
|
|
|
<tgroup cols="3">
|
|
<thead>
|
|
<row>
|
|
<entry>Concept</entry>
|
|
<entry>Refines</entry>
|
|
<entry>Models</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.ReadWriteLock">ReadWriteLock</link></entry>
|
|
<entry></entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link></entry>
|
|
<entry><link linkend="threads.concepts.ReadWriteLock">ReadWriteLock</link></entry>
|
|
<entry>
|
|
<para><classname>boost::read_write_mutex::scoped_read_write_lock</classname></para>
|
|
<para><classname>boost::try_read_write_mutex::scoped_read_write_lock</classname></para>
|
|
<para><classname>boost::timed_read_write_mutex::scoped_read_write_lock</classname></para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.TryReadWriteLock">TryReadWriteLock</link></entry>
|
|
<entry><link linkend="threads.concepts.ReadWriteLock">ReadWriteLock</link></entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.ScopedTryReadWriteLock">ScopedTryReadWriteLock</link></entry>
|
|
<entry><link linkend="threads.concepts.TryReadWriteLock">TryReadWriteLock</link></entry>
|
|
<entry>
|
|
<para><classname>boost::try_read_write_mutex::scoped_try_read_write_lock</classname></para>
|
|
<para><classname>boost::timed_read_write_mutex::scoped_try_read_write_lock</classname></para>
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.TimedReadWriteLock">TimedReadWriteLock</link></entry>
|
|
<entry><link linkend="threads.concepts.TryReadWriteLock">TryReadWriteLock</link></entry>
|
|
<entry></entry>
|
|
</row>
|
|
<row>
|
|
<entry><link linkend="threads.concepts.ScopedTimedReadWriteLock">ScopedTimedReadWriteLock</link></entry>
|
|
<entry><link linkend="threads.concepts.TimedReadWriteLock">TimedReadWriteLock</link></entry>
|
|
<entry>
|
|
<para><classname>boost::timed_read_write_mutex::scoped_timed_read_write_lock</classname></para>
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
</section>
|
|
</section>
|