1
0
Fork 0
cl-sites/w3.cs.jmu.edu/kirkpams/OpenCSF/Books/csf/html/Condvars.html
2025-01-28 10:11:14 +01:00

796 lines
No EOL
55 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>7.6. Condition Variables &mdash; Computer Systems Fundamentals</title>
<link rel="stylesheet" href="_static/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />
<link rel="stylesheet" href="_static/css/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/css/normalize.css" type="text/css" />
<link rel="stylesheet" href="../../../JSAV/css/JSAV.css" type="text/css" />
<link rel="stylesheet" href="../../../lib/odsaMOD-min.css" type="text/css" />
<link rel="stylesheet" href="_static/css/jquery-1.11.4-smoothness-ui.css" type="text/css" />
<link rel="stylesheet" href="../../../lib/odsaStyle-min.css" type="text/css" />
<link rel="stylesheet" href="_static/css/csf.css" type="text/css" />
<style>
.underline { text-decoration: underline; }
</style>
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.4.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [['$','$'], ['\\(','\\)']],
displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
processEscapes: true
},
"HTML-CSS": {
scale: "80"
}
});
</script>
<link rel="shortcut icon" href="_static/favicon.ico"/>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="index" title="Computer Systems Fundamentals" href="index.html" />
<link rel="next" title="7. Deadlock" href="Deadlock.html" />
<link rel="prev" title="5. Barriers" href="Barriers.html" />
</head><body>
<nav class="navbar navbar-expand-md navbar-dark navbar-custom fixed-top">
<a class="navbar-brand py-0" href="index.html"><img src="_static/CSF-Logo-Square-Text.png" alt="OpenCSF Logo" height="40em" class="py-1 px-2 mb-0 align-center rounded-lg bg-white" /></a>
<!-- Show a navbar toggler on mobile -->
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#defaultNavbars" aria-controls="defaultNavbars" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="defaultNavbars">
<ul class="navbar-nav mr-auto">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle jmu-gold rounded" href="Condvars.html#" id="navbarDropdownChapters" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Contents</a>
<div class="dropdown-menu scrollable-menu" role="menu" aria-labelledby="navbarDropdownChapters">
<a class="dropdown-item" tabindex="-1" href="Condvars.html#"><b>Chapter 1</b></a>
<a class="dropdown-item" href="IntroConcSysOverview.html">&nbsp;&nbsp;&nbsp;1.1. Introduction to Concurrent Systems</a>
<a class="dropdown-item" href="SysAndModels.html">&nbsp;&nbsp;&nbsp;1.2. Systems and Models</a>
<a class="dropdown-item" href="Themes.html">&nbsp;&nbsp;&nbsp;1.3. Themes and Guiding Principles</a>
<a class="dropdown-item" href="Architectures.html">&nbsp;&nbsp;&nbsp;1.4. System Architectures</a>
<a class="dropdown-item" href="StateModels.html">&nbsp;&nbsp;&nbsp;1.5. State Models in UML</a>
<a class="dropdown-item" href="SequenceModels.html">&nbsp;&nbsp;&nbsp;1.6. Sequence Models in UML</a>
<a class="dropdown-item" href="StateModelImplementation.html">&nbsp;&nbsp;&nbsp;1.7. Extended Example: State Model Implementation</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 2</b></a>
<a class="dropdown-item" href="ProcessesOverview.html">&nbsp;&nbsp;&nbsp;2.1. Processes and OS Basics</a>
<a class="dropdown-item" href="Multiprogramming.html">&nbsp;&nbsp;&nbsp;2.2. Processes and Multiprogramming</a>
<a class="dropdown-item" href="KernelMechanics.html">&nbsp;&nbsp;&nbsp;2.3. Kernel Mechanics</a>
<a class="dropdown-item" href="Syscall.html">&nbsp;&nbsp;&nbsp;2.4. System Call Interface</a>
<a class="dropdown-item" href="ProcessCycle.html">&nbsp;&nbsp;&nbsp;2.5. Process Life Cycle</a>
<a class="dropdown-item" href="UnixFile.html">&nbsp;&nbsp;&nbsp;2.6. The UNIX File Abstraction</a>
<a class="dropdown-item" href="EventsSignals.html">&nbsp;&nbsp;&nbsp;2.7. Events and Signals</a>
<a class="dropdown-item" href="Extended2Processes.html">&nbsp;&nbsp;&nbsp;2.8. Extended Example: Listing Files with Processes</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 3</b></a>
<a class="dropdown-item" href="IPCOverview.html">&nbsp;&nbsp;&nbsp;3.1. Concurrency with IPC</a>
<a class="dropdown-item" href="IPCModels.html">&nbsp;&nbsp;&nbsp;3.2. IPC Models</a>
<a class="dropdown-item" href="Pipes.html">&nbsp;&nbsp;&nbsp;3.3. Pipes and FIFOs</a>
<a class="dropdown-item" href="MMap.html">&nbsp;&nbsp;&nbsp;3.4. Shared Memory With Memory-mapped Files</a>
<a class="dropdown-item" href="POSIXvSysV.html">&nbsp;&nbsp;&nbsp;3.5. POSIX vs. System V IPC</a>
<a class="dropdown-item" href="MQueues.html">&nbsp;&nbsp;&nbsp;3.6. Message Passing With Message Queues</a>
<a class="dropdown-item" href="ShMem.html">&nbsp;&nbsp;&nbsp;3.7. Shared Memory</a>
<a class="dropdown-item" href="IPCSems.html">&nbsp;&nbsp;&nbsp;3.8. Semaphores</a>
<a class="dropdown-item" href="Extended3Bash.html">&nbsp;&nbsp;&nbsp;3.9. Extended Example: Bash-lite: A Simple Command-line Shell</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 4</b></a>
<a class="dropdown-item" href="SocketsOverview.html">&nbsp;&nbsp;&nbsp;4.1. Networked Concurrency</a>
<a class="dropdown-item" href="FiveLayer.html">&nbsp;&nbsp;&nbsp;4.2. The TCP/IP Internet Model</a>
<a class="dropdown-item" href="NetApps.html">&nbsp;&nbsp;&nbsp;4.3. Network Applications and Protocols</a>
<a class="dropdown-item" href="Sockets.html">&nbsp;&nbsp;&nbsp;4.4. The Socket Interface</a>
<a class="dropdown-item" href="TCPSockets.html">&nbsp;&nbsp;&nbsp;4.5. TCP Socket Programming: HTTP</a>
<a class="dropdown-item" href="UDPSockets.html">&nbsp;&nbsp;&nbsp;4.6. UDP Socket Programming: DNS</a>
<a class="dropdown-item" href="AppBroadcast.html">&nbsp;&nbsp;&nbsp;4.7. Application-Layer Broadcasting: DHCP</a>
<a class="dropdown-item" href="Extended4CGI.html">&nbsp;&nbsp;&nbsp;4.8. Extended Example: CGI Web Server</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 5</b></a>
<a class="dropdown-item" href="InternetOverview.html">&nbsp;&nbsp;&nbsp;5.1. The Internet and Connectivity</a>
<a class="dropdown-item" href="AppLayer.html">&nbsp;&nbsp;&nbsp;5.2. Application Layer: Overlay Networks</a>
<a class="dropdown-item" href="TransLayer.html">&nbsp;&nbsp;&nbsp;5.3. Transport Layer</a>
<a class="dropdown-item" href="NetSec.html">&nbsp;&nbsp;&nbsp;5.4. Network Security Fundamentals</a>
<a class="dropdown-item" href="NetLayer.html">&nbsp;&nbsp;&nbsp;5.5. Network Layer: IP</a>
<a class="dropdown-item" href="LinkLayer.html">&nbsp;&nbsp;&nbsp;5.6. Link Layer</a>
<a class="dropdown-item" href="Wireless.html">&nbsp;&nbsp;&nbsp;5.7. Wireless Connectivity: Wi-Fi, Bluetooth, and Zigbee</a>
<a class="dropdown-item" href="Extended5DNS.html">&nbsp;&nbsp;&nbsp;5.8. Extended Example: DNS client</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 6</b></a>
<a class="dropdown-item" href="ThreadsOverview.html">&nbsp;&nbsp;&nbsp;6.1. Concurrency with Multithreading</a>
<a class="dropdown-item" href="ProcVThreads.html">&nbsp;&nbsp;&nbsp;6.2. Processes vs. Threads</a>
<a class="dropdown-item" href="RaceConditions.html">&nbsp;&nbsp;&nbsp;6.3. Race Conditions and Critical Sections</a>
<a class="dropdown-item" href="POSIXThreads.html">&nbsp;&nbsp;&nbsp;6.4. POSIX Thread Library</a>
<a class="dropdown-item" href="ThreadArgs.html">&nbsp;&nbsp;&nbsp;6.5. Thread Arguments and Return Values</a>
<a class="dropdown-item" href="ImplicitThreads.html">&nbsp;&nbsp;&nbsp;6.6. Implicit Threading and Language-based Threads</a>
<a class="dropdown-item" href="Extended6Input.html">&nbsp;&nbsp;&nbsp;6.7. Extended Example: Keyboard Input Listener</a>
<a class="dropdown-item" href="Extended6Primes.html">&nbsp;&nbsp;&nbsp;6.8. Extended Example: Concurrent Prime Number Search</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 7</b></a>
<a class="dropdown-item" href="SynchOverview.html">&nbsp;&nbsp;&nbsp;7.1. Synchronization Primitives</a>
<a class="dropdown-item" href="CritSect.html">&nbsp;&nbsp;&nbsp;7.2. Critical Sections and Peterson's Solution</a>
<a class="dropdown-item" href="Locks.html">&nbsp;&nbsp;&nbsp;7.3. Locks</a>
<a class="dropdown-item" href="Semaphores.html">&nbsp;&nbsp;&nbsp;7.4. Semaphores</a>
<a class="dropdown-item" href="Barriers.html">&nbsp;&nbsp;&nbsp;7.5. Barriers</a>
<a class="dropdown-item" href="Condvars.html">&nbsp;&nbsp;&nbsp;7.6. Condition Variables</a>
<a class="dropdown-item" href="Deadlock.html">&nbsp;&nbsp;&nbsp;7.7. Deadlock</a>
<a class="dropdown-item" href="Extended7Events.html">&nbsp;&nbsp;&nbsp;7.8. Extended Example: Event Log File</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 8</b></a>
<a class="dropdown-item" href="SynchProblemsOverview.html">&nbsp;&nbsp;&nbsp;8.1. Synchronization Patterns and Problems</a>
<a class="dropdown-item" href="SynchDesign.html">&nbsp;&nbsp;&nbsp;8.2. Basic Synchronization Design Patterns</a>
<a class="dropdown-item" href="ProdCons.html">&nbsp;&nbsp;&nbsp;8.3. Producer-Consumer Problem</a>
<a class="dropdown-item" href="ReadWrite.html">&nbsp;&nbsp;&nbsp;8.4. Readers-Writers Problem</a>
<a class="dropdown-item" href="DiningPhil.html">&nbsp;&nbsp;&nbsp;8.5. Dining Philosophers Problem and Deadlock</a>
<a class="dropdown-item" href="CigSmokers.html">&nbsp;&nbsp;&nbsp;8.6. Cigarette Smokers Problem and the Limits of Semaphores and Locks</a>
<a class="dropdown-item" href="Extended8ModExp.html">&nbsp;&nbsp;&nbsp;8.7. Extended Example: Parallel Modular Exponentiation</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 9</b></a>
<a class="dropdown-item" href="ParallelDistributedOverview.html">&nbsp;&nbsp;&nbsp;9.1. Parallel and Distributed Systems</a>
<a class="dropdown-item" href="ParVConc.html">&nbsp;&nbsp;&nbsp;9.2. Parallelism vs. Concurrency</a>
<a class="dropdown-item" href="ParallelDesign.html">&nbsp;&nbsp;&nbsp;9.3. Parallel Design Patterns</a>
<a class="dropdown-item" href="Scaling.html">&nbsp;&nbsp;&nbsp;9.4. Limits of Parallelism and Scaling</a>
<a class="dropdown-item" href="DistTiming.html">&nbsp;&nbsp;&nbsp;9.5. Timing in Distributed Environments</a>
<a class="dropdown-item" href="DistDataStorage.html">&nbsp;&nbsp;&nbsp;9.6. Reliable Data Storage and Location</a>
<a class="dropdown-item" href="DistConsensus.html">&nbsp;&nbsp;&nbsp;9.7. Consensus in Distributed Systems</a>
<a class="dropdown-item" href="Extended9Blockchain.html">&nbsp;&nbsp;&nbsp;9.8. Extended Example: Blockchain Proof-of-Work</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Appendix A</b></a>
<a class="dropdown-item" href="CLangOverview.html">&nbsp;&nbsp;&nbsp;A.1. C Language Reintroduction</a>
<a class="dropdown-item" href="Debugging.html">&nbsp;&nbsp;&nbsp;A.2. Documentation and Debugging</a>
<a class="dropdown-item" href="BasicTypes.html">&nbsp;&nbsp;&nbsp;A.3. Basic Types and Pointers</a>
<a class="dropdown-item" href="Arrays.html">&nbsp;&nbsp;&nbsp;A.4. Arrays, Structs, Enums, and Type Definitions</a>
<a class="dropdown-item" href="Functions.html">&nbsp;&nbsp;&nbsp;A.5. Functions and Scope</a>
<a class="dropdown-item" href="Pointers.html">&nbsp;&nbsp;&nbsp;A.6. Pointers and Dynamic Allocation</a>
<a class="dropdown-item" href="Strings.html">&nbsp;&nbsp;&nbsp;A.7. Strings</a>
<a class="dropdown-item" href="FunctionPointers.html">&nbsp;&nbsp;&nbsp;A.8. Function Pointers</a>
<a class="dropdown-item" href="Files.html">&nbsp;&nbsp;&nbsp;A.9. Files</a>
</div>
</li>
</ul>
</div>
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
<li class="nav-item"><a class="nav-link jmu-gold" href="https://w3.cs.jmu.edu/kirkpams/OpenCSF/Books/csf/source/Condvars.rst"
target="_blank" rel="nofollow">Show Source</a></li>
</ul>
</nav>
<div class="container center">
«&#160;&#160;<a id="prevmod" href="Barriers.html">7.5. Barriers</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a id="nextmod" href="Deadlock.html">7.7. Deadlock</a>&#160;&#160;»
</div>
<br />
<script type="text/javascript" src="_static/js/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/javascript" src="_static/js/jquery-1.11.4-ui.min.js"></script>
<script type="text/javascript" src="_static/js/forge-0.7.0.min.js"></script>
<script type="text/javascript" src="../../../JSAV/lib/jquery.transit.js"></script>
<script type="text/javascript" src="../../../JSAV/lib/raphael.js"></script>
<script type="text/javascript" src="../../../JSAV/build/JSAV-min.js"></script>
<script type="text/javascript" src="_static/js/config.js"></script>
<script type="text/javascript" src="../../../lib/odsaUtils-min.js"></script>
<script type="text/javascript" src="../../../lib/odsaMOD-min.js"></script>
<script type="text/javascript" src="_static/js/d3-4.13.0.min.js"></script>
<script type="text/javascript" src="_static/js/d3-selection-multi.v1.min.js"></script>
<script type="text/javascript" src="../../../lib/dataStructures.js"></script>
<div class="container">
<script>ODSA.SETTINGS.DISP_MOD_COMP = true;ODSA.SETTINGS.MODULE_NAME = "Condvars";ODSA.SETTINGS.MODULE_LONG_NAME = "Condition Variables";ODSA.SETTINGS.MODULE_CHAPTER = "Synchronization Primitives"; ODSA.SETTINGS.BUILD_DATE = "2021-06-01 15:31:50"; ODSA.SETTINGS.BUILD_CMAP = false;JSAV_OPTIONS['lang']='en';JSAV_EXERCISE_OPTIONS['code']='java';</script><div class="section" id="condition-variables">
<h1>7.6. Condition Variables<a class="headerlink" href="Condvars.html#condition-variables" title="Permalink to this headline"></a></h1>
<p>One of the primary uses of semaphores is to perform application-specific
signaling. One thread waits on a semaphore until another thread indicates that
some important event has occurred. While semaphores are flexible, they have a
number of short-comings for many programs.</p>
<blockquote>
<div><ul class="simple">
<li>Semaphore operations do not adhere to strong principles of encapsulation and
abstraction. That is, the practice of incrementing and decrementing an integer
value does not have an obvious mapping to synchronization problems. For
instance, this contrasts with the more intuitive <em>lock</em> and <em>unlock</em> operations
on mutex locks.</li>
<li>There are several different implementations of semaphores that vary in the
features that they provide. Furthermore, different systems provide varying
levels of support and compliance in their semaphore implementations.</li>
<li>In most implementations, semaphores can only send a signal to one other thread
(or process) at a time. Semaphores provide no mechanism for broadcasting
messages to multiple other threads.</li>
<li>When receiving a signal, threads have to perform an extra step to secure
mutually exclusive access to shared data. The delay in the timing between the
signal and acquiring the mutex can introduce race conditions.</li>
</ul>
</div></blockquote>
<p><a class="reference internal" href="Glossary.html#term-condition-variable"><span class="xref std std-term">Condition variables</span></a> overcome many of these
short-comings of semaphores. Similar to the POSIX semaphore interface, condition
variables provide <em>wait</em> and <em>signal</em> functions. These provide a more natural
mapping to the problems of synchronization, as one or more threads are waiting
on a signal from another thread that a condition has occurred.</p>
<div class="topic border border-dark rounded-lg bg-light px-2 mb-3">
<div class="figure align-left">
<a class="reference internal image-reference" href="_images/CSF-Images-Library.png"><img alt="Decorative C library image" src="_images/CSF-Images-Library.png" style="width: 100%;" /></a>
</div>
<p class="topic-title first pt-2 mb-1">C library functions &lt;pthread.h&gt;</p><hr class="mt-1" />
<dl class="docutils">
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">pthread_cond_init</span> <span class="pre">(pthread_cond_t</span> <span class="pre">*cond,</span> <span class="pre">const</span> <span class="pre">pthread_condattr_t</span> <span class="pre">*attr);</span></code></dt>
<dd>Initialize a condition variable.</dd>
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">pthread_cond_wait</span> <span class="pre">(pthread_cond_t</span> <span class="pre">*cond,</span> <span class="pre">pthread_mutex_t</span> <span class="pre">*mutex);</span></code></dt>
<dd>Release a mutex, wait on a condition, then re-acquire the mutex.</dd>
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">pthread_cond_signal</span> <span class="pre">(pthread_cond_t</span> <span class="pre">*cond);</span></code></dt>
<dd>Send a signal to a waiting thread.</dd>
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">pthread_cond_broadcast</span> <span class="pre">(pthread_cond_t</span> <span class="pre">*cond);</span></code></dt>
<dd>Send a signal to all waiting threads.</dd>
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">pthread_cond_destroy</span> <span class="pre">(pthread_cond_t</span> <span class="pre">*cond);</span></code></dt>
<dd>Delete a condition variable and clean up its associated resources.</dd>
</dl>
</div>
<div class="section" id="condition-variables-vs-semaphores">
<h2>7.6.1. Condition Variables vs. Semaphores<a class="headerlink" href="Condvars.html#condition-variables-vs-semaphores" title="Permalink to this headline"></a></h2>
<p>Condition variables and semaphores appear very similar, as they both provide a
mechanism that allow threads to signal that a custom event has occurred. But the
differences between condition variables and semaphore signaling go beyond just a
shift in terminology.</p>
<blockquote>
<div><ul class="simple">
<li>The <code class="docutils literal notranslate"><span class="pre">pthread_cond_wait()</span></code> function performs multiple functions. It first
releases the mutex and blocks until the corresponding signal is received; it
then re-acquires the mutex that had been locked. Specifically, both of these
actions are considered to occur atomically; unless an error occurs, the thread
is guaranteed to have acquired the mutex by the time the function returns.</li>
<li>Condition variables support broadcasting. The <code class="docutils literal notranslate"><span class="pre">pthread_cond_broadcast()</span></code>
function will notify all threads that are waiting on the condition. Moreover,
each thread will resume one at a time with the mutex acquired. With the
additional mutual exclusion guarantees, condition variables can be combined in
a thread-safe manner with other pieces of data to make the condition more meaningful.</li>
<li>Condition variables are a standard part of the POSIX thread library, and they
are more widely supported. For instance, some systems include the unnamed POSIX
semaphore interface, but the implementation is empty, as named semaphores are
preferred. There is no similar distinction in condition variables, and there is
wider support for them.</li>
</ul>
</div></blockquote>
</div>
<div class="section" id="how-to-use-a-condition-variable">
<h2>7.6.2. How to Use a Condition Variable<a class="headerlink" href="Condvars.html#how-to-use-a-condition-variable" title="Permalink to this headline"></a></h2>
<p>There are several conventional practices for condition variables that may not be immediately obvious.</p>
<blockquote>
<div><ul class="simple">
<li>A thread must acquire the mutex before calling <code class="docutils literal notranslate"><span class="pre">pthread_cond_wait()</span></code>, which
will release the mutex. Calling <code class="docutils literal notranslate"><span class="pre">pthread_cond_wait()</span></code> without having locked
the mutex leads to undefined behavior.</li>
<li>Calls to <code class="docutils literal notranslate"><span class="pre">pthread_cond_wait()</span></code> should be made inside a while loop. The POSIX
specification allows threads to wake up even if the signal was not sent (called
a <em>spurious wake up</em>). By checking the return value of <code class="docutils literal notranslate"><span class="pre">pthread_cond_wait()</span></code>,
the thread can determine if the wake up was spurious and go back to waiting if necessary.</li>
<li>Just calling <code class="docutils literal notranslate"><span class="pre">pthread_cond_signal()</span></code> or <code class="docutils literal notranslate"><span class="pre">pthread_cond_broadcast()</span></code> is
insufficient to wake up waiting threads, as the threads are locked by the mutex
rather than the condition variable. The functions must be followed by a call to
<code class="docutils literal notranslate"><span class="pre">pthread_mutex_unlock()</span></code>, which will allow <code class="docutils literal notranslate"><span class="pre">pthread_cond_wait()</span></code> to acquire
the mutex and return.</li>
</ul>
</div></blockquote>
</div>
<div class="section" id="a-condition-variable-example">
<h2>7.6.3. A Condition Variable Example<a class="headerlink" href="Condvars.html#a-condition-variable-example" title="Permalink to this headline"></a></h2>
<p>The following sample program uses one thread read lines of keyboard input from
<code class="docutils literal notranslate"><span class="pre">STDIN</span></code>, then passing on the information to two other threads. If the input is
a string, the second thread gets the length of the string and adds it to a
counter. If the input can be converted to an long using <code class="docutils literal notranslate"><span class="pre">strtol()</span></code>, then the
integer value is added to the counter by the third thread.</p>
<p>The threads all rely on the following shared <code class="docutils literal notranslate"><span class="pre">struct</span></code>. The <code class="docutils literal notranslate"><span class="pre">input_cond</span></code>
condition variable is used to indicate that a line of input has been received.
The <code class="docutils literal notranslate"><span class="pre">input_processed_cond</span></code> variable is used to indicate that the two helper
threads have processed the input and the keyboard listener can get more input.
The other fields are used to pass information between the threads.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
2
3
4
5
6
7
8
9
10
11
12
13</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cp">#define MAX_LENGTH 100</span>
<span class="cm">/* Common struct with pointers to all variables needed */</span>
<span class="k">struct</span> <span class="n">args</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">counter</span><span class="p">;</span>
<span class="n">pthread_cond_t</span> <span class="o">*</span><span class="n">input_cond</span><span class="p">;</span>
<span class="n">pthread_cond_t</span> <span class="o">*</span><span class="n">input_processed_cond</span><span class="p">;</span>
<span class="n">pthread_mutex_t</span> <span class="o">*</span><span class="n">mutex</span><span class="p">;</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">buffer</span><span class="p">;</span>
<span class="kt">long</span> <span class="n">current_value</span><span class="p">;</span>
<span class="kt">bool</span> <span class="n">shutdown</span><span class="p">;</span>
<span class="kt">bool</span> <span class="n">input_is_string</span><span class="p">;</span>
<span class="p">};</span>
</pre></div>
</td></tr></table></div>
<p>The keyboard listener starts by acquiring the mutex, guaranteeing that this
thread has mutually exclusive access to the shared data. After reading a line of
input with <code class="docutils literal notranslate"><span class="pre">fgets()</span></code>, this thread tries to convert the input to an long with
<code class="docutils literal notranslate"><span class="pre">strtol()</span></code>. If so, it sets the current_value field to this integer value. If
not, the string is checked against the string <code class="docutils literal notranslate"><span class="pre">&quot;shutdown&quot;</span></code>, which is used to
make the program stop. In all three cases, <code class="docutils literal notranslate"><span class="pre">pthread_cond_broadcast()</span></code> signals
to the other threads that input has been received. The listener then waits on
the <code class="docutils literal notranslate"><span class="pre">input_processed_cond</span></code> condition, which indicates that the input has been
processed completely by another thread. Finally, if the shutdown message was
received, this thread sets a boolean value that the others detect during another
broadcast. <a class="reference external" href="Condvars.html#cl7-15">Code Listing 7.15</a> shows the keyboard listener thread.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl7-15"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 7.15:</span>
<span class="cm"> A thread that uses condition variable broadcasting to share data</span>
<span class="cm"> */</span>
<span class="cm">/* Keyboard listener thread; gets input and signals to helper </span>
<span class="cm"> threads */</span>
<span class="kt">void</span> <span class="o">*</span>
<span class="nf">keyboard_listener</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">_args</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">struct</span> <span class="n">args</span> <span class="o">*</span><span class="n">args</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">args</span> <span class="o">*</span><span class="p">)</span> <span class="n">_args</span><span class="p">;</span>
<span class="cm">/* With condvars, always acquire the lock before waiting */</span>
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span>
<span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="p">{</span>
<span class="cm">/* Get input from the user */</span>
<span class="n">printf</span> <span class="p">(</span><span class="s">&quot;Enter a string/number (or shutdown to quit): &quot;</span><span class="p">);</span>
<span class="n">memset</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">buffer</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">MAX_LENGTH</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">fgets</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">buffer</span><span class="p">,</span> <span class="n">MAX_LENGTH</span><span class="p">,</span> <span class="n">stdin</span><span class="p">)</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>
<span class="k">break</span><span class="p">;</span>
<span class="cm">/* Check for a numeric value or &quot;shutdown&quot; */</span>
<span class="kt">long</span> <span class="n">guess</span> <span class="o">=</span> <span class="n">strtol</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">buffer</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="mi">10</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">guess</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">args</span><span class="o">-&gt;</span><span class="n">current_value</span> <span class="o">=</span> <span class="n">guess</span><span class="p">;</span>
<span class="n">args</span><span class="o">-&gt;</span><span class="n">input_is_string</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">strncmp</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">buffer</span><span class="p">,</span> <span class="s">&quot;shutdown&quot;</span><span class="p">,</span> <span class="mi">8</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">args</span><span class="o">-&gt;</span><span class="n">input_is_string</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="k">else</span>
<span class="k">break</span><span class="p">;</span>
<span class="cm">/* Send signal to all waiting threads */</span>
<span class="n">pthread_cond_broadcast</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">input_cond</span><span class="p">);</span>
<span class="cm">/* Wait for confirmation the input is processed */</span>
<span class="n">pthread_cond_wait</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">input_processed_cond</span><span class="p">,</span> <span class="n">args</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span>
<span class="n">flush_buffer</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">buffer</span><span class="p">);</span>
<span class="p">}</span>
<span class="cm">/* Send the shutdown input condition */</span>
<span class="n">args</span><span class="o">-&gt;</span><span class="n">shutdown</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="n">pthread_cond_broadcast</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">input_cond</span><span class="p">);</span>
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span>
<span class="n">pthread_exit</span> <span class="p">(</span><span class="nb">NULL</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
<p><a class="reference external" href="Condvars.html#cl7-16">Code Listing 7.16</a> shows the additional threads that share this
data. The <code class="docutils literal notranslate"><span class="pre">count_chars()</span></code> and <code class="docutils literal notranslate"><span class="pre">add_number()</span></code> threads behave in approximately
the same manner. They both start by acquiring the mutex, then waiting on the
<code class="docutils literal notranslate"><span class="pre">input_cond</span></code>. In both cases, the call to <code class="docutils literal notranslate"><span class="pre">pthread_cond_wait()</span></code> releases the
lock at this point. Once the signal has been received and the mutex is
re-acquired, the threads check if they need to shutdown. If not, they each check
if the input was a string. Only the <code class="docutils literal notranslate"><span class="pre">count_chars()</span></code> thread processes string
input, whereas only the <code class="docutils literal notranslate"><span class="pre">add_number()</span></code> thread processes numeric input. If the
thread is not supposed to process input, it uses continue to go back to the
beginning of the loop and wait on the condition again. If the thread did process
its appropriate input, it signals on the <code class="docutils literal notranslate"><span class="pre">input_processed_cond</span></code> variable,
which allows <code class="docutils literal notranslate"><span class="pre">keyboard_listener()</span></code> to move on to reading the next line of input.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl7-16"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 7.16:</span>
<span class="cm"> Threads that process data as it is received via a condition variable</span>
<span class="cm"> */</span>
<span class="cm">/* Thread for counting characters in a string */</span>
<span class="kt">void</span> <span class="o">*</span>
<span class="nf">count_chars</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">_args</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">struct</span> <span class="n">args</span> <span class="o">*</span><span class="n">args</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">args</span> <span class="o">*</span><span class="p">)</span> <span class="n">_args</span><span class="p">;</span>
<span class="cm">/* With condvars, always acquire the lock before waiting */</span>
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span>
<span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="p">{</span>
<span class="cm">/* Wait on the input condition */</span>
<span class="n">pthread_cond_wait</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">input_cond</span><span class="p">,</span> <span class="n">args</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span>
<span class="cm">/* Signal received, mutex has been re-acquired */</span>
<span class="cm">/* If the input was shutdown signal, quit */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">shutdown</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>
<span class="cm">/* If the input was a number, ignore this signal */</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">input_is_string</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
<span class="cm">/* Input was string not shutdown; get length without \n */</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">newline</span> <span class="o">=</span> <span class="n">strchr</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">buffer</span><span class="p">,</span> <span class="sc">&#39;\n&#39;</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">newline</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="o">*</span><span class="n">newline</span> <span class="o">=</span> <span class="sc">&#39;\0&#39;</span><span class="p">;</span>
<span class="n">args</span><span class="o">-&gt;</span><span class="n">counter</span> <span class="o">+=</span> <span class="n">strlen</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">buffer</span><span class="p">);</span>
<span class="cm">/* Restore the newline for buffer flushing */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">newline</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="o">*</span><span class="n">newline</span> <span class="o">=</span> <span class="sc">&#39;\n&#39;</span><span class="p">;</span>
<span class="cm">/* Signal back to keyboard listener that input processing </span>
<span class="cm"> is done */</span>
<span class="n">pthread_cond_signal</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">input_processed_cond</span><span class="p">);</span>
<span class="cm">/* Do NOT unlock mutex; pthread_cond_wait() will do that */</span>
<span class="p">}</span>
<span class="cm">/* Shutting down. Send acknowledgement signal back */</span>
<span class="n">pthread_cond_signal</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">input_processed_cond</span><span class="p">);</span>
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span>
<span class="n">pthread_exit</span> <span class="p">(</span><span class="nb">NULL</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="o">*</span>
<span class="nf">add_number</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">_args</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">struct</span> <span class="n">args</span> <span class="o">*</span><span class="n">args</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">args</span> <span class="o">*</span><span class="p">)</span> <span class="n">_args</span><span class="p">;</span>
<span class="cm">/* With condvars, always acquire the lock before waiting */</span>
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span>
<span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="p">{</span>
<span class="cm">/* Wait on the input condition */</span>
<span class="n">pthread_cond_wait</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">input_cond</span><span class="p">,</span> <span class="n">args</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span>
<span class="cm">/* Signal received, mutex has been re-acquired */</span>
<span class="cm">/* If the input was shutdown signal, quit */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">shutdown</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>
<span class="cm">/* If the input was a string, ignore this signal */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">input_is_string</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
<span class="cm">/* Add current value to the counter and send signal back */</span>
<span class="n">args</span><span class="o">-&gt;</span><span class="n">counter</span> <span class="o">+=</span> <span class="n">args</span><span class="o">-&gt;</span><span class="n">current_value</span><span class="p">;</span>
<span class="n">pthread_cond_signal</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">input_processed_cond</span><span class="p">);</span>
<span class="cm">/* Do NOT unlock mutex; pthread_cond_wait() will do that */</span>
<span class="p">}</span>
<span class="cm">/* Shutting down. Send acknowledgement signal back */</span>
<span class="n">pthread_cond_signal</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">input_processed_cond</span><span class="p">);</span>
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span>
<span class="n">pthread_exit</span> <span class="p">(</span><span class="nb">NULL</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
<div class="topic border border-dark rounded-lg alert-danger px-2 mb-3">
<div class="figure align-left">
<a class="reference internal image-reference" href="_images/CSF-Images-BugWarning.png"><img alt="Decorative bug warning" src="_images/CSF-Images-BugWarning.png" style="width: 90%;" /></a>
</div>
<p class="topic-title first pt-2 mb-1">Bug Warning</p><hr class="mt-1" />
<p>For completeness, both the <code class="docutils literal notranslate"><span class="pre">count_chars()</span></code> and <code class="docutils literal notranslate"><span class="pre">add_number()</span></code> threads should
check the return value of <code class="docutils literal notranslate"><span class="pre">pthread_cond_wait()</span></code> to determine if the signal
was spurious. However, this code omits this check for brevity and algorithmic clarity.</p>
</div>
<p>Finally, <a class="reference external" href="Condvars.html#cl7-17">Code Listing 7.17</a> illustrates how to initialize the
condition variables, create the threads, and clean up all of the resources for
the condition variables and the mutex.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl7-17"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 7.17:</span>
<span class="cm"> Initializing a condition variable and other data structures</span>
<span class="cm"> */</span>
<span class="n">pthread_t</span> <span class="n">threads</span><span class="p">[</span><span class="mi">3</span><span class="p">];</span>
<span class="n">pthread_cond_t</span> <span class="n">input_cond</span><span class="p">;</span>
<span class="n">pthread_cond_t</span> <span class="n">input_processed_cond</span><span class="p">;</span>
<span class="n">pthread_mutex_t</span> <span class="n">mutex</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="n">MAX_LENGTH</span> <span class="o">+</span> <span class="mi">1</span><span class="p">];</span>
<span class="cm">/* Initialize the mutex and the condition variables */</span>
<span class="n">pthread_mutex_init</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">mutex</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="n">pthread_cond_init</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">input_cond</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="n">pthread_cond_init</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">input_processed_cond</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="cm">/* Set up the args for all threads */</span>
<span class="k">struct</span> <span class="n">args</span> <span class="n">args</span><span class="p">;</span>
<span class="n">args</span><span class="p">.</span><span class="n">counter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">args</span><span class="p">.</span><span class="n">input_cond</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">input_cond</span><span class="p">;</span>
<span class="n">args</span><span class="p">.</span><span class="n">input_processed_cond</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">input_processed_cond</span><span class="p">;</span>
<span class="n">args</span><span class="p">.</span><span class="n">mutex</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">mutex</span><span class="p">;</span>
<span class="n">args</span><span class="p">.</span><span class="n">buffer</span> <span class="o">=</span> <span class="n">buffer</span><span class="p">;</span>
<span class="n">args</span><span class="p">.</span><span class="n">current_value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">args</span><span class="p">.</span><span class="n">shutdown</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="n">args</span><span class="p">.</span><span class="n">input_is_string</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="cm">/* Create and join the threads */</span>
<span class="n">assert</span> <span class="p">(</span><span class="n">pthread_create</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">threads</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">count_chars</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">args</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">);</span>
<span class="n">assert</span> <span class="p">(</span><span class="n">pthread_create</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">threads</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">add_number</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">args</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">);</span>
<span class="n">assert</span> <span class="p">(</span><span class="n">pthread_create</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">threads</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">keyboard_listener</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">args</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">);</span>
<span class="n">pthread_join</span> <span class="p">(</span><span class="n">threads</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="n">pthread_join</span> <span class="p">(</span><span class="n">threads</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="n">pthread_join</span> <span class="p">(</span><span class="n">threads</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="nb">NULL</span><span class="p">);</span>
<span class="cm">/* Print out total, destroy the mutex and condition variables */</span>
<span class="n">printf</span> <span class="p">(</span><span class="s">&quot;Total: %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">args</span><span class="p">.</span><span class="n">counter</span><span class="p">);</span>
<span class="n">pthread_mutex_destroy</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">mutex</span><span class="p">);</span>
<span class="n">pthread_cond_destroy</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">input_cond</span><span class="p">);</span>
<span class="n">pthread_cond_destroy</span> <span class="p">(</span><span class="o">&amp;</span><span class="n">input_processed_cond</span><span class="p">);</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="section" id="monitors-and-synchronized-methods">
<h2>7.6.4. Monitors and Synchronized Methods<a class="headerlink" href="Condvars.html#monitors-and-synchronized-methods" title="Permalink to this headline"></a></h2>
<div class="figure mb-2 align-right" id="id1" style="width: 45%">
<span id="synchmonitor"></span><a class="reference internal image-reference" href="_images/CSF-Images.7.2.png"><img class="p-3 mb-2 align-center border border-dark rounded-lg" alt="Architecture of a monitor with synchronized data access" src="_images/CSF-Images.7.2.png" style="width: 90%;" /></a>
<p class="caption align-center px-3"><span class="caption-text"> Figure 7.6.3: Architecture of a monitor with synchronized data access</span></p>
</div>
<p>The preceding code is an example of an object-oriented construct known as a
monitor. <a href="Condvars.html#synchmonitor">Figure 7.6.3</a> illustrates the general
architecture of a <a class="reference internal" href="Glossary.html#term-monitor"><span class="xref std std-term">monitor</span></a>. Specifically, a monitor is a class or data
structure that combines condition variables, mutexes, and other
application-specific data. All of the internal data is considered private to the
monitor, and other pieces of code can only interact with the monitor by invoking
a method on the object.</p>
<p>The key characteristic of a monitor is that all methods are mutually exclusive
in execution. That is, as with the thread functions above, methods in a monitor
begin by locking the monitors mutex. Doing so guarantees that only one thread
is <em>in the monitor</em> at any given moment. The method ends by releasing the mutex,
allowing other threads to enter the monitor.</p>
<p>Within the monitor, there are associated condition variables to synchronize
access between the monitor and the general execution environment. While the
methods are executing, they can use these condition variables to detect key
events or to check for safe conditions. If the condition variable check (i.e.,
<code class="docutils literal notranslate"><span class="pre">pthread_cond_wait()</span></code>) fails, then the thread must release the mutex and exit
the monitor. The thread then waits in the condition variables associated
waiting queue until it can resume execution.</p>
<p>Readers familiar with the Java synchronized keyword have been essentially using
monitors by a different name. That is, the primary function of the synchronized
keyword is to have injected code that acquires a hidden mutex at the beginning
of the method execution, then releases it when returning.</p>
<div
id="SynchCondvarSumm"
class="embedContainer"
data-exer-name="SynchCondvarSumm"
data-long-name="Condition variable questions"
data-short-name="SynchCondvarSumm"
data-frame-src="../../../Exercises/Synch/SynchCondvarSumm.html?selfLoggingEnabled=false&amp;localMode=true&amp;module=Condvars&amp;JXOP-debug=true&amp;JOP-lang=en&amp;JXOP-code=java"
data-frame-width="950"
data-frame-height="550"
data-external="false"
data-points="1.0"
data-required="True"
data-showhide="show"
data-threshold="5"
data-type="ka"
data-exer-id="">
<div class="center">
<div id="SynchCondvarSumm_iframe"></div>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<div class="mt-4 container center">
«&#160;&#160;<a id="prevmod1" href="Barriers.html">7.5. Barriers</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a id="nextmod1" href="Deadlock.html">7.7. Deadlock</a>&#160;&#160;»
</div>
</div>
<br />
<div class="row jmu-dark-purple-bg">
<div class="col-md-12">
<center>
<a id="contact_us" class="btn button-link-no-blue jmu-gold" rel="nofollow" href="mailto:webmaster@opencsf.org" role="button">Contact Us</a>
<a id="license" class="btn button-link-no-blue jmu-gold" rel="nofollow" href="https://w3.cs.jmu.edu/kirkpams/OpenCSF/lib/license.html" target="_blank">License</a>
</center>
</div>
</div>
<script src="_static/js/popper.js-1.14.7-min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="_static/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>