mirror of
https://github.com/boostorg/thread.git
synced 2026-01-23 18:12:12 +00:00
227 lines
7.8 KiB
HTML
227 lines
7.8 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, semaphore</title>
|
|
</head>
|
|
|
|
<body bgcolor="#ffffff" link="#0000ff" vlink="#800080">
|
|
|
|
<table border="0" cellpadding="7" cellspacing="0" width="100%">
|
|
<tr>
|
|
<td valign="top" width="300">
|
|
<h3><IMG height=86 alt="C++ Boost" src="../../../c++boost.gif" width=277></h3>
|
|
</td>
|
|
<td valign="top">
|
|
<h1 align="center">Boost.Threads</h1>
|
|
<h2 align="center">semaphore</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>The <tt>semaphore</tt> class defines a classic synchronization primitive invented by the
|
|
Dutch computer scientist Edsger W. Dijkstra. A semaphore manages an internal counter. This
|
|
counter never goes below zero, or above a specified maximum value. When calling
|
|
<tt>semaphore::down</tt> the calling thread will block until the value is non-zero and then
|
|
decrement the value in a single atomic operation. When calling <tt>semaphore::up</tt> the
|
|
calling thread will increment the value in a single atomic operation, failing if the value has
|
|
already reached the specified maximum.</p>
|
|
|
|
<p><b>Rationale:</b> The semaphore is the simplest synchronization primitive available and is generally the
|
|
primitive used to build other synchronization concepts at some level of implementation. For this
|
|
reason <b>Boost.Threads</b> defines the <tt>semaphore</tt> type in the classic form. This simplifies
|
|
usage and implementation, but it means that the interface is not as safe as other <b>Boost.Threads</b>
|
|
interfaces.</p>
|
|
|
|
<p><b><a name="Danger">Danger</a>:</b> Unlike the <A href="mutex_concept.html">mutex models</a> supplied by <b>Boost.Threads,</b>
|
|
there is no <A href="lock_concept.html">lock_concept</a> for the semaphore to help ensure proper
|
|
usage. Great care must be taken when using a <tt>semaphore</tt> object to ensure
|
|
<a href="definitions.html#Deadlock"> deadlock</a> or <a href="definitions.html#Race condition">race conditions</a> do not occur. </p>
|
|
|
|
<p>The dangers are spelled out by <a href="bibliography.html#Andrews-83">[Andrews-83]</a>
|
|
(function names updated, see historical note below): </p>
|
|
|
|
<blockquote>
|
|
|
|
<p>Although semaphores can be used to program almost any kind of synchronization,
|
|
<b>down()</b> and <b>up()</b> are rather unstructured primitives, and so it is easy to err when using them. Execution of each critical section must begin with a
|
|
<b>down()</b> and end with a <b>up()</b> (on the same semaphore). Omitting a <b>down()</b>
|
|
or <b>up()</b>, or accidentally coding a <b>down()</b> on one semaphore and a <b>up()</b>
|
|
on another can have disastrous effects, since mutually exclusive execution would no longer be ensured. Also, when using semaphores, a programmer can forget to include in critical sections all statements that reference shared objects. This, too, could destroy the mutual exclusion required within critical sections. A second difficulty with using semaphores is that both condition synchronization and mutual exclusion are programmed using the same pair of primitives. This makes it difficult to identify the purpose of a given
|
|
<b>down()</b> or <b>up()</b> operation without looking at the other operations on the corresponding semaphore. Since mutual exclusion and condition synchronization are distinct concepts, they should have distinct notations.</p>
|
|
|
|
</blockquote>
|
|
|
|
<p><b>Historical note: </b>Dijkstra's original name for <b>down()</b> was <b>P</b>
|
|
(short for the Dutch "passeren", "to pass"), and for <b>up()</b>
|
|
was <b>V</b> (short for the Dutch "vrygeven", "to release").</p>
|
|
|
|
<h2><a name="Header">Header</a></h2>
|
|
|
|
<pre>
|
|
#include <a href="../../../boost/thread/semaphore.hpp"><boost/thread/semaphore.hpp></a>
|
|
</pre>
|
|
|
|
<h2><a name="Synopsis">Synopsis</a></h2>
|
|
|
|
<pre>
|
|
namespace boost
|
|
{
|
|
class semaphore : private <a href="../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
|
|
// Class semaphore meets the <a href="overview.html#NonCopyable">NonCopyable</a> requirement.
|
|
{
|
|
public:
|
|
explicit semaphore(unsigned count=0, unsigned max=0);
|
|
~semaphore();
|
|
|
|
bool up(unsigned count=1, unsigned* prev=0);
|
|
void down();
|
|
bool down(const xtime& xt);
|
|
private:
|
|
unsigned m_count; <i>exposition only [ISO 17.3.2.3/2]
|
|
</i> unsigned m_max; <i>exposition only [ISO 17.3.2.3/2]</i>
|
|
};
|
|
}
|
|
</pre>
|
|
|
|
<h2><a name="Members">Members</a></h2>
|
|
|
|
<hr>
|
|
|
|
<h3>Constructor</h3>
|
|
|
|
<pre>
|
|
explicit semaphore(unsigned count=0, unsigned max=0);
|
|
</pre>
|
|
|
|
<p><b>Effects:</b> As if:</p>
|
|
|
|
<p><code> m_count = count;<br>
|
|
m_max = (max == 0 ? std::numeric_limits<unsigned>::max()
|
|
? max );</code></p>
|
|
|
|
<hr>
|
|
|
|
<h3>Destructor</h3>
|
|
|
|
<pre>
|
|
~semaphore();
|
|
</pre>
|
|
|
|
<p><b>Effects:</b> Destroys <code>*this</code>.</p>
|
|
|
|
<hr>
|
|
|
|
<h3>up</h3>
|
|
|
|
<pre>
|
|
bool up(unsigned count=1, unsigned* prev=0);
|
|
</pre>
|
|
|
|
<p><b>Effects:</b> As if:</p>
|
|
|
|
<p><code> unsigned ct;<br>
|
|
bool ret;<br>
|
|
{ // as a single atomic operation:<br>
|
|
ct = m_count;<br>
|
|
if (m_count == m_max) ret =
|
|
false;<br>
|
|
else<br>
|
|
{<br>
|
|
ret =
|
|
true;<br>
|
|
++m_count;<br>
|
|
}<br>
|
|
}<br>
|
|
if (prev) *prev = m_count;<br>
|
|
return ret;</code></p>
|
|
|
|
<hr>
|
|
|
|
<h3>down</h3>
|
|
|
|
<pre>
|
|
void down();
|
|
</pre>
|
|
|
|
<p><b>Effects:</b> If <code>m_count == 0</code>, places the current thread in
|
|
the <a href="definitions.html#State">blocked</a> state until <code>m_count != 0</code>.
|
|
Finally, <code>--m_count</code>.<code> </code></p>
|
|
|
|
<hr>
|
|
|
|
<pre>
|
|
bool down(const <a href="xtime.html">xtime</a>& xt);
|
|
</pre>
|
|
|
|
<p><b>Effects:</b> If <code>m_count == 0</code>, places the current thread in
|
|
the <a href="definitions.html#State">blocked</a> state until <code>m_count != 0</code>
|
|
or <code>xt</code> is reached. Finally, <code>--m_count</code>.<code> </code></p>
|
|
|
|
<p><b>Returns:</b> If xt was reached, true, else false.</p>
|
|
|
|
<hr>
|
|
|
|
<h2><a name="Example">Example</a> Usage</h2>
|
|
|
|
<pre>
|
|
#include <a href="../../../boost/thread/semaphore.hpp"><boost/thread/semaphore.hpp></a>
|
|
#include <a href="../../../boost/thread/thread.hpp"><boost/thread/thread.hpp></a>
|
|
#include <iostream>
|
|
|
|
int global_data = 0;
|
|
boost::semaphore global_semaphore(1);
|
|
|
|
void change_global_data(void*)
|
|
{
|
|
global_semaphore.down();
|
|
++global_data;
|
|
std::cout << "global_data == " << global_data << std::endl;
|
|
global_semaphore.up();
|
|
}
|
|
|
|
int main(int, char*[])
|
|
{
|
|
const int num_threads = 4;
|
|
boost::thread_group thrds;
|
|
for (int i=0; i < num_threads; ++i)
|
|
thrds.create_thread(&change_global_data, 0);
|
|
|
|
thrds.join_all();
|
|
|
|
return 0;
|
|
}
|
|
</pre>
|
|
|
|
<p>The output is:</p>
|
|
|
|
<pre>
|
|
global_data == 1
|
|
global_data == 2
|
|
global_data == 3
|
|
global_data == 4
|
|
</pre>
|
|
|
|
<hr>
|
|
|
|
<p>Revised <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->13 September, 2001<!--webbot bot="Timestamp" endspan i-checksum="39334" -->
|
|
</p>
|
|
|
|
<p><i>© Copyright <A href="mailto:williamkempf@hotmail.com">William E. Kempf</a>
|
|
2001 all rights reserved.</i></p>
|
|
|
|
</body>
|
|
</html>
|