mirror of
https://github.com/boostorg/thread.git
synced 2026-01-22 05:42:37 +00:00
339 lines
12 KiB
HTML
339 lines
12 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++">
|
|
<link rel="stylesheet" type="text/css" href="styles.css">
|
|
|
|
<title>Boost.Threads, condition</title>
|
|
</head>
|
|
|
|
<body bgcolor="#ffffff" link="#0000ff" vlink="#800080" text="#000000">
|
|
<table summary="header" 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">condition</h2>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
<hr>
|
|
|
|
<p><a href="#Introduction">Introduction</a><br>
|
|
<a href="#Header">Header</a><br>
|
|
<a href="#Synopsis">Synopsis</a><br>
|
|
<a href="#Members">Members</a><br>
|
|
<a href="#Example">Example</a></p>
|
|
|
|
<h2><a name="Introduction">Introduction</a></h2>
|
|
|
|
<p>An object of class <code>condition</code> is a synchronization
|
|
primitive used to cause a thread to wait until a particular shared-data
|
|
condition (or time) is met. A <code>condition</code> object is always
|
|
used in conjunction with a mutex object modeling a <a href=
|
|
"mutex_concept.html">Mutex Concept</a>. The mutex must be locked prior
|
|
to waiting on the <code>condition</code>, which is ensured by passing a
|
|
lock object modeling a <a href="lock_concept.html">Lock Concept</a> to
|
|
the <code>condition</code> object's <code>wait</code> functions.
|
|
While the thread is waiting on the <code>condition</code> object, the
|
|
mutex associated with the lock is unlocked. When the thread returns
|
|
from a call to one of the <code>condition</code> object's <code>
|
|
wait</code> functions, the mutex is again locked. The tricky
|
|
lock/unlock/lock sequence is performed automatically by the <code>
|
|
condition</code> object's <code>wait</code> functions.</p>
|
|
|
|
<p>The <code>condition</code> type is often used to implement the <i>
|
|
Monitor Object</i> and other important patterns. See <a href=
|
|
"bibliography.html#Schmidt-00">[Schmidt-00]</a> and <a href=
|
|
"bibliography.html#Hoare-74">[Hoare 74]</a>. Monitors are one of the
|
|
most important patterns for creating reliable multithreaded
|
|
programs.</p>
|
|
|
|
<p>See <a href="definitions.html">Formal Definitions</a> for
|
|
definitions of thread states <a href="definitions.html#state">
|
|
blocked</a> and <a href="definitions.html#state">ready</a>. Note that
|
|
"waiting" is a synonym for blocked.</p>
|
|
|
|
<h2><a name="Header">Header</a></h2>
|
|
<pre>
|
|
#include <a href=
|
|
"../../../boost/thread/condition.hpp"><boost/thread/condition.hpp></a>
|
|
</pre>
|
|
|
|
<h2><a name="Synopsis">Synopsis</a></h2>
|
|
<pre>
|
|
namespace boost {
|
|
|
|
class condition : private <a href=
|
|
"../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
|
// Class condition meets the <a href=
|
|
"overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
{
|
|
public:
|
|
condition();
|
|
~condition();
|
|
|
|
void notify_one();
|
|
void notify_all();
|
|
template <typename <a href="scoped_lock.html">ScopedLock</a>>
|
|
void wait(<a href="scoped_lock.html">ScopedLock</a>& lock);
|
|
template <typename <a href="scoped_lock.html">ScopedLock</a>, typename <a
|
|
href="http://www.sgi.com/tech/stl/Predicate.html">Predicate</a>>
|
|
void wait(<a href="scoped_lock.html">ScopedLock</a>& lock, <a href=
|
|
"http://www.sgi.com/tech/stl/Predicate.html">Predicate</a> pred);
|
|
template <typename <a href="scoped_lock.html">ScopedLock</a>>
|
|
bool timed_wait(<a href=
|
|
"scoped_lock.html">ScopedLock</a>& lock, const xtime& xt);
|
|
template <typename <a href="scoped_lock.html">ScopedLock</a>, typename <a
|
|
href="http://www.sgi.com/tech/stl/Predicate.html">Predicate</a>>
|
|
bool timed_wait(<a href=
|
|
"scoped_lock.html">ScopedLock</a>& lock, const xtime& xt, <a href=
|
|
"http://www.sgi.com/tech/stl/Predicate.html">Predicate</a> pred);
|
|
};
|
|
|
|
} // namespace boost
|
|
</pre>
|
|
|
|
<h2><a name="Members">Members</a></h2>
|
|
<hr>
|
|
|
|
<h3>Constructor</h3>
|
|
<pre>
|
|
condition();
|
|
</pre>
|
|
|
|
<p><b>Effects:</b> Constructs a <code>condition</code>.</p>
|
|
<hr>
|
|
|
|
<h3>Destructor</h3>
|
|
<pre>
|
|
~condition();
|
|
</pre>
|
|
|
|
<p><b>Effects:</b> Destroys <code>*this</code>.</p>
|
|
<hr>
|
|
|
|
<h3>notify_one</h3>
|
|
<pre>
|
|
void notify_one();
|
|
</pre>
|
|
|
|
<p><b>Effects:</b> If there is a thread waiting on <code>*this</code>,
|
|
change that thread's state to ready. Otherwise there is no
|
|
effect.</p>
|
|
|
|
<p><b>Notes:</b> If more that one thread is waiting on the condition,
|
|
it is unspecified which is made ready.</p>
|
|
<hr>
|
|
|
|
<h3>notify_all</h3>
|
|
<pre>
|
|
void notify_all();
|
|
</pre>
|
|
|
|
<p><b>Effects:</b> Change the state of all threads waiting on <code>
|
|
*this</code> to ready. If there are no waiting threads, <code>
|
|
notify_all()</code> has no effect.</p>
|
|
<hr>
|
|
|
|
<h3>wait</h3>
|
|
<pre>
|
|
template <typename ScopedLock>
|
|
void wait(ScopedLock& lock);
|
|
</pre>
|
|
|
|
<p><b>Requires:</b> ScopedLock meets the <a href=
|
|
"lock_concept.html#ScopedLock">ScopedLock</a> requirements.</p>
|
|
|
|
<p><b>Effects:</b> Releases the lock on the <a href=
|
|
"mutex_concept.html">mutex model</a> associated with <code>lock</code>,
|
|
blocks the current thread of execution until readied by a call to
|
|
<code>this->notify_one()</code> or <code>
|
|
this->notify_all()</code>, and then reacquires the lock. All effects
|
|
occur in an atomic fashion.</p>
|
|
|
|
<p><b>Throws:</b> <code><a href="lock_error.html">lock_error</a></code>
|
|
if <code>!lock.locked()</code></p>
|
|
|
|
<p><b>Danger:</b> This version should always be used within a loop
|
|
checking that the state logically associated with the <code>
|
|
condition</code> has become true. Without the loop, race conditions can
|
|
ensue due to possible "spurious wake ups". The second version
|
|
encapsulates this loop idiom internally and is generally the preferred
|
|
method.</p>
|
|
<pre>
|
|
template <typename ScopedLock, typename Pr>
|
|
void wait(ScopedLock& lock, Pr pred);
|
|
</pre>
|
|
|
|
<p><b>Requires:</b> ScopedLock meets the <a href=
|
|
"lock_concept.html#ScopedLock">ScopedLock</a> requirements, return from
|
|
<code>pred()</code> convertible to bool.</p>
|
|
|
|
<p><b>Effects:</b> As if:</p>
|
|
<code> while (!pred()) wait(lock)</code>
|
|
|
|
<p><b>Throws:</b> <code><a href="lock_error.html">lock_error</a></code>
|
|
if <code>!lock.locked()</code></p>
|
|
<hr>
|
|
|
|
<h3>timed_wait</h3>
|
|
<pre>
|
|
template <typename ScopedLock>
|
|
bool timed_wait(ScopedLock& lock, const <a href=
|
|
"xtime.html">xtime</a>& xt);
|
|
</pre>
|
|
|
|
<p><b>Requires:</b> ScopedLock meets the <a href=
|
|
"lock_concept.html#ScopedLock">ScopedLock</a>
|
|
requirements.</p>
|
|
|
|
<p><b>Effects:</b> Releases the lock on the <a href=
|
|
"mutex_concept.html">mutex model</a> associated with the <code>
|
|
lock</code>, blocks the current thread of execution until readied by a
|
|
call to <code>this->notify_one()</code> or <code>
|
|
this->notify_all()</code>, or until <code>xt</code>, and then
|
|
reacquires the lock. All effects occur in an atomic fashion.</p>
|
|
|
|
<p><b>Throws:</b> <code><a href="lock_error.html">lock_error</a></code>
|
|
if <code>!lock.locked()</code></p>
|
|
|
|
<p><b>Danger:</b> This version should always be used within a loop
|
|
checking that the state logically associated with the <code>
|
|
condition</code> has become true. Without the loop, race conditions can
|
|
ensue due to "spurious wake ups". The second version
|
|
encapsulates this loop idiom internally and is generally the preferred
|
|
method.</p>
|
|
|
|
<p><b>Returns:</b> <code>false</code> if <code>xt</code> is reached,
|
|
otherwise <code>true</code>.</p>
|
|
<pre>
|
|
template <typename ScopedLock, typename Pr>
|
|
bool timed_wait(ScopedLock& lock, const <a href=
|
|
"xtime.html">xtime</a>& xt, Pr pred);
|
|
</pre>
|
|
|
|
<p><b>Requires:</b> ScopedLock meets the <a href=
|
|
"lock_concept.html#ScopedLock">ScopedLock</a> requirements,
|
|
return from <code>pred()</code> convertible to bool.</p>
|
|
|
|
<p><b>Effects:</b> As if:</p>
|
|
<code> while (!pred())<br>
|
|
{<br>
|
|
if (!timed_wait(lock, xt))<br>
|
|
return
|
|
false;<br>
|
|
}</code>
|
|
|
|
<p><b>Throws:</b> <code><a href="lock_error.html">lock_error</a></code>
|
|
if <code>!lock.locked()</code></p>
|
|
|
|
<p><b>Returns:</b> <code>false</code> if <code>xt</code> is reached,
|
|
otherwise <code>true</code>.</p>
|
|
<hr>
|
|
|
|
<h2><a name="Example">Example Usage</a></h2>
|
|
<pre>
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <a href="../../../boost/utility.hpp"><boost/utility.hpp></a>
|
|
#include <a href=
|
|
"../../../boost/thread/condition.hpp"><boost/thread/condition.hpp></a>
|
|
#include <a href=
|
|
"../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
|
|
|
class bounded_buffer : private boost::noncopyable
|
|
{
|
|
public:
|
|
typedef boost::mutex::scoped_lock lock;
|
|
|
|
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
|
|
|
|
void send (int m) {
|
|
lock lk(monitor);
|
|
while (buffered == circular_buf.size())
|
|
buffer_not_full.wait(lk);
|
|
circular_buf[end] = m;
|
|
end = (end+1) % circular_buf.size();
|
|
++buffered;
|
|
buffer_not_empty.notify_one();
|
|
}
|
|
int receive() {
|
|
lock lk(monitor);
|
|
while (buffered == 0)
|
|
buffer_not_empty.wait(lk);
|
|
int i = circular_buf[begin];
|
|
begin = (begin+1) % circular_buf.size();
|
|
--buffered;
|
|
buffer_not_full.notify_one();
|
|
return i;
|
|
}
|
|
|
|
private:
|
|
int begin, end, buffered;
|
|
std::vector<int> circular_buf;
|
|
boost::condition buffer_not_full, buffer_not_empty;
|
|
boost::mutex monitor;
|
|
};
|
|
|
|
bounded_buffer buf(2);
|
|
|
|
void sender() {
|
|
int n = 0;
|
|
while (n < 100) {
|
|
buf.send(n);
|
|
std::cout << "sent: " << n << std::endl;
|
|
++n;
|
|
}
|
|
buf.send(-1);
|
|
}
|
|
|
|
void receiver() {
|
|
int n;
|
|
do {
|
|
n = buf.receive();
|
|
std::cout << "received: " << n << std::endl;
|
|
} while (n != -1); // -1 indicates end of buffer
|
|
}
|
|
|
|
int main(int, char*[])
|
|
{
|
|
boost::thread thrd1(&sender);
|
|
boost::thread thrd2(&receiver);
|
|
thrd1.join();
|
|
thrd2.join();
|
|
return 0;
|
|
}
|
|
</pre>
|
|
|
|
<p>Typical output (dependent on scheduling policies) is:</p>
|
|
<pre>
|
|
sent: 0
|
|
sent: 1
|
|
received: 0
|
|
received: 1
|
|
sent: 2
|
|
sent: 3
|
|
received: 2
|
|
received: 3
|
|
sent: 4
|
|
received: 4
|
|
</pre>
|
|
<hr>
|
|
|
|
<p>Revised
|
|
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->05 November, 2001<!--webbot bot="Timestamp" endspan i-checksum="39359" --></p>
|
|
|
|
<p><i>© Copyright <a href="mailto:williamkempf@hotmail.com">
|
|
William E. Kempf</a> 2001 all rights reserved.</i></p>
|
|
</body>
|
|
</html>
|
|
|