2
0
mirror of https://github.com/boostorg/thread.git synced 2026-01-31 08:42:17 +00:00
Files
thread/doc/condition.html
2001-07-17 21:22:21 +00:00

311 lines
9.2 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 border="0" cellpadding="7" cellspacing="0" width="100%">
<tr>
<td valign="top" width="300">
<h3><img src="../../../c++boost.gif" alt="C++ Boost" width="277" height="86"></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>A <tt>condition</tt> is a synchronization primitive used to cause a thread to
wait until a particular condition (or time)&nbsp; is met. A <tt>condition</tt> always works in
conjunction with a <a href="mutex_concept.html">mutex model</a>. The
<a href="mutex_concept.html">mutex model</a> must be locked prior to waiting on the <tt>condition</tt>,
which is insured by passing a <a href="lock_concept.html">lock model</a> to the <code>condition</code> class <tt>wait</tt> functions. While the thread is waiting on the <tt>condition</tt> the
<a href="mutex_concept.html">mutex model</a> is unlocked. When the thread returns from a call
to one of the <code>condition</code> class <tt>wait</tt> functions, the <a href="mutex_concept.html">mutex model</a> is again
locked.</p>
<p>The <tt>condition</tt> type is often used to implement the
<i>Monitor Object</i> pattern. See <a href="bibliography.html#Schmidt-00">[Schmidt
00]</a>&nbsp;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="thread_formal_definition.html"> Formal Definitions</a> for definitions of thread states <a href="thread_formal_definition.html#state">blocked</a>
and <a href="thread_formal_definition.html#state">ready</a>. Note that
&quot;waiting&quot; is a synonym for blocked.</p>
<h2><a name="Header">Header</a></h2>
<pre>
#include <a href="../../../boost/thread/condition.hpp">&lt;boost/thread/condition.hpp&gt;</a>
</pre>
<h2><a name="Synopsis">Synopsis</a></h2>
<pre>namespace boost
{
class condition : private noncopyable
{
public:
condition();
~condition();
void notify_one();
void notify_all();
template &lt;typename L&gt;
void wait(L&amp; lock);
template &lt;typename L, typename Pr&gt;
void wait(L&amp; lock, Pr pred);
template &lt;typename L&gt;
bool timed_wait(L&amp; lock, const xtime&amp; xt);
template &lt;typename L, typename Pr&gt;
bool timed_wait(L&amp; lock, const xtime&amp; xt, Pr pred);
};
}</pre>
<h2><a name="Members">Members</a></h2>
<hr>
<h3>Constructor</h3>
<pre>
condition();
</pre>
<p><b>Effects: </b>Constructs a <tt>condition</tt>.</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.<b>&nbsp;</b> 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.&nbsp;</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()</code> has no effect.</p>
<hr>
<h3>wait</h3>
<pre>
template &lt;typename L&gt;
void wait(L&amp; lock);
</pre>
<p><b>Requires: </b>L meet the requirements of the <a href="lock_concept.html">Lock
concept</a>.</p>
<p><b>Effects: </b>Releases the lock on the <a href="mutex_concept.html">mutex model</a> associated with <tt>lock</tt>,
blocks the current thread of execution until readied by a call to <code>*this-&gt;notify()</code>
or <code>*this-&gt;notify_all()</code>, and then reacquires the lock.&nbsp; 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</code></p>
<p><b>Danger: </b>This version should always be used within a loop checking that the state logically associated
with the <tt>condition</tt> 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 &lt;typename L, typename Pr&gt;
void wait(L&amp; lock, Pr pred);
</pre>
<p><b>Requires: </b>L meet the requirements of the <a href="lock_concept.html">Lock
concept</a>. Return from <code>pred()</code> convertible to bool.</p>
<p><b>Effects: </b>As if: <code>while !(pred()) wait(lock)</code></p>
<p><b>Throws:</b> <code><a href="lock_error.html">lock_error</a></code> if <code>!lock</code></p>
<hr>
<h3>timed_wait</h3>
<pre>
template &lt;typename L&gt;
bool timed_wait(L&amp; lock, const xtime&amp; xt);
</pre>
<p><b>Requires: </b>L meet the requirements of the <a href="lock_concept.html">Lock
concept</a>.</p>
<p><b>Effects: </b>Releases the lock on the <a href="mutex_concept.html">mutex model</a> associated with the <tt>lock</tt>,
blocks the current thread of execution until readied by a call to <code>*this-&gt;notify()</code>
or <code>*this-&gt;notify_all()</code>, or until <tt>xt,</tt> and then reacquires the lock.&nbsp; 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</code></p>
<p><b>Danger:</b> This version should
always be used within a loop checking that the state logically associated with the <tt>condition</tt> 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> <tt>false</tt> if <code>xt </code>expires, otherwise <code>true</code>.&nbsp;</p>
<pre>
template &lt;typename L, typename Pr&gt;
bool timed_wait(L&amp; lock, const xtime&amp; xt, Pr pred);
</pre>
<p><b>Requires: </b>L meet the requirements of the <a href="lock_concept.html">Lock
concept</a>.&nbsp; Return from <code>pred()</code> convertible to bool.</p>
<p><b>Effects: </b>As if: <b>&nbsp;</b></p>
<pre> while (!pred())
{
if (!timed_wait(lock, xt))
return false;
}
</pre>
<p><b>Throws:</b> <code><a href="lock_error.html">lock_error</a></code> if <code>!lock</code></p>
<p><b>Returns:</b> <tt>false</tt> if <code>xt </code>expires, otherwise <code>true</code>.</p>
<hr>
<h2><a name="Example">Example</a> Usage</h2>
<pre>
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include <a href="../../../boost/utility.hpp">&lt;boost/utility.hpp&gt;</a>
#include <a href="../../../boost/thread/condition.hpp">&lt;boost/thread/condition.hpp&gt;</a>
#include <a href="../../../boost/thread/thread.hpp">&lt;boost/thread/thread.hpp&gt;</a>
class bounded_buffer : private boost::noncopyable
{
private:
int begin, end, buffered;
std::vector&lt;int&gt; circular_buf;
boost::condition buffer_not_full, buffer_not_empty;
boost::mutex monitor;
typedef boost::mutex::lock lock;
public:
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 &amp;&amp; !finished)
buffer_not_empty.wait(lk);
int i = circular_buf[begin];
begin = (begin+1) % circular_buf.size();
--buffered;
buffer_not_full.notify_one();
return i;
}
};
bounded_buffer buf(2);
void sender(void*) {
int n = 0;
while (n &lt; 100) {
buf.send(n);
std::cout &lt;&lt; &quot;sent: &quot; &lt;&lt; n &lt;&lt; std::endl;
++n;
}
buf.send(-1);
}
void receiver(void*) {
int n;
do {
n = buf.receive();
std::cout &lt;&lt; &quot;received: &quot; &lt;&lt; n &lt;&lt; std::endl;
} while (n != -1); // -1 indicates end of buffer
}
int main(int, char*[])
{
boost::thread::create(&amp;sender, 0);
boost::thread::create(&amp;receiver, 0);
boost::thread::join_all();
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 -->17 July, 2001<!--webbot bot="Timestamp" endspan i-checksum="21075" -->
</p>
<p><i>Copyright <a href="mailto:williamkempf@hotmail.com">William E. Kempf</a>
2001 all rights reserved.</i></p>
</body>
</html>