796 lines
No EOL
55 KiB
HTML
796 lines
No EOL
55 KiB
HTML
|
||
<!DOCTYPE html>
|
||
|
||
|
||
|
||
|
||
<html lang="en">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||
|
||
<title>7.6. Condition Variables — 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"> 1.1. Introduction to Concurrent Systems</a>
|
||
<a class="dropdown-item" href="SysAndModels.html"> 1.2. Systems and Models</a>
|
||
<a class="dropdown-item" href="Themes.html"> 1.3. Themes and Guiding Principles</a>
|
||
<a class="dropdown-item" href="Architectures.html"> 1.4. System Architectures</a>
|
||
<a class="dropdown-item" href="StateModels.html"> 1.5. State Models in UML</a>
|
||
<a class="dropdown-item" href="SequenceModels.html"> 1.6. Sequence Models in UML</a>
|
||
<a class="dropdown-item" href="StateModelImplementation.html"> 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"> 2.1. Processes and OS Basics</a>
|
||
<a class="dropdown-item" href="Multiprogramming.html"> 2.2. Processes and Multiprogramming</a>
|
||
<a class="dropdown-item" href="KernelMechanics.html"> 2.3. Kernel Mechanics</a>
|
||
<a class="dropdown-item" href="Syscall.html"> 2.4. System Call Interface</a>
|
||
<a class="dropdown-item" href="ProcessCycle.html"> 2.5. Process Life Cycle</a>
|
||
<a class="dropdown-item" href="UnixFile.html"> 2.6. The UNIX File Abstraction</a>
|
||
<a class="dropdown-item" href="EventsSignals.html"> 2.7. Events and Signals</a>
|
||
<a class="dropdown-item" href="Extended2Processes.html"> 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"> 3.1. Concurrency with IPC</a>
|
||
<a class="dropdown-item" href="IPCModels.html"> 3.2. IPC Models</a>
|
||
<a class="dropdown-item" href="Pipes.html"> 3.3. Pipes and FIFOs</a>
|
||
<a class="dropdown-item" href="MMap.html"> 3.4. Shared Memory With Memory-mapped Files</a>
|
||
<a class="dropdown-item" href="POSIXvSysV.html"> 3.5. POSIX vs. System V IPC</a>
|
||
<a class="dropdown-item" href="MQueues.html"> 3.6. Message Passing With Message Queues</a>
|
||
<a class="dropdown-item" href="ShMem.html"> 3.7. Shared Memory</a>
|
||
<a class="dropdown-item" href="IPCSems.html"> 3.8. Semaphores</a>
|
||
<a class="dropdown-item" href="Extended3Bash.html"> 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"> 4.1. Networked Concurrency</a>
|
||
<a class="dropdown-item" href="FiveLayer.html"> 4.2. The TCP/IP Internet Model</a>
|
||
<a class="dropdown-item" href="NetApps.html"> 4.3. Network Applications and Protocols</a>
|
||
<a class="dropdown-item" href="Sockets.html"> 4.4. The Socket Interface</a>
|
||
<a class="dropdown-item" href="TCPSockets.html"> 4.5. TCP Socket Programming: HTTP</a>
|
||
<a class="dropdown-item" href="UDPSockets.html"> 4.6. UDP Socket Programming: DNS</a>
|
||
<a class="dropdown-item" href="AppBroadcast.html"> 4.7. Application-Layer Broadcasting: DHCP</a>
|
||
<a class="dropdown-item" href="Extended4CGI.html"> 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"> 5.1. The Internet and Connectivity</a>
|
||
<a class="dropdown-item" href="AppLayer.html"> 5.2. Application Layer: Overlay Networks</a>
|
||
<a class="dropdown-item" href="TransLayer.html"> 5.3. Transport Layer</a>
|
||
<a class="dropdown-item" href="NetSec.html"> 5.4. Network Security Fundamentals</a>
|
||
<a class="dropdown-item" href="NetLayer.html"> 5.5. Network Layer: IP</a>
|
||
<a class="dropdown-item" href="LinkLayer.html"> 5.6. Link Layer</a>
|
||
<a class="dropdown-item" href="Wireless.html"> 5.7. Wireless Connectivity: Wi-Fi, Bluetooth, and Zigbee</a>
|
||
<a class="dropdown-item" href="Extended5DNS.html"> 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"> 6.1. Concurrency with Multithreading</a>
|
||
<a class="dropdown-item" href="ProcVThreads.html"> 6.2. Processes vs. Threads</a>
|
||
<a class="dropdown-item" href="RaceConditions.html"> 6.3. Race Conditions and Critical Sections</a>
|
||
<a class="dropdown-item" href="POSIXThreads.html"> 6.4. POSIX Thread Library</a>
|
||
<a class="dropdown-item" href="ThreadArgs.html"> 6.5. Thread Arguments and Return Values</a>
|
||
<a class="dropdown-item" href="ImplicitThreads.html"> 6.6. Implicit Threading and Language-based Threads</a>
|
||
<a class="dropdown-item" href="Extended6Input.html"> 6.7. Extended Example: Keyboard Input Listener</a>
|
||
<a class="dropdown-item" href="Extended6Primes.html"> 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"> 7.1. Synchronization Primitives</a>
|
||
<a class="dropdown-item" href="CritSect.html"> 7.2. Critical Sections and Peterson's Solution</a>
|
||
<a class="dropdown-item" href="Locks.html"> 7.3. Locks</a>
|
||
<a class="dropdown-item" href="Semaphores.html"> 7.4. Semaphores</a>
|
||
<a class="dropdown-item" href="Barriers.html"> 7.5. Barriers</a>
|
||
<a class="dropdown-item" href="Condvars.html"> 7.6. Condition Variables</a>
|
||
<a class="dropdown-item" href="Deadlock.html"> 7.7. Deadlock</a>
|
||
<a class="dropdown-item" href="Extended7Events.html"> 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"> 8.1. Synchronization Patterns and Problems</a>
|
||
<a class="dropdown-item" href="SynchDesign.html"> 8.2. Basic Synchronization Design Patterns</a>
|
||
<a class="dropdown-item" href="ProdCons.html"> 8.3. Producer-Consumer Problem</a>
|
||
<a class="dropdown-item" href="ReadWrite.html"> 8.4. Readers-Writers Problem</a>
|
||
<a class="dropdown-item" href="DiningPhil.html"> 8.5. Dining Philosophers Problem and Deadlock</a>
|
||
<a class="dropdown-item" href="CigSmokers.html"> 8.6. Cigarette Smokers Problem and the Limits of Semaphores and Locks</a>
|
||
<a class="dropdown-item" href="Extended8ModExp.html"> 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"> 9.1. Parallel and Distributed Systems</a>
|
||
<a class="dropdown-item" href="ParVConc.html"> 9.2. Parallelism vs. Concurrency</a>
|
||
<a class="dropdown-item" href="ParallelDesign.html"> 9.3. Parallel Design Patterns</a>
|
||
<a class="dropdown-item" href="Scaling.html"> 9.4. Limits of Parallelism and Scaling</a>
|
||
<a class="dropdown-item" href="DistTiming.html"> 9.5. Timing in Distributed Environments</a>
|
||
<a class="dropdown-item" href="DistDataStorage.html"> 9.6. Reliable Data Storage and Location</a>
|
||
<a class="dropdown-item" href="DistConsensus.html"> 9.7. Consensus in Distributed Systems</a>
|
||
<a class="dropdown-item" href="Extended9Blockchain.html"> 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"> A.1. C Language Reintroduction</a>
|
||
<a class="dropdown-item" href="Debugging.html"> A.2. Documentation and Debugging</a>
|
||
<a class="dropdown-item" href="BasicTypes.html"> A.3. Basic Types and Pointers</a>
|
||
<a class="dropdown-item" href="Arrays.html"> A.4. Arrays, Structs, Enums, and Type Definitions</a>
|
||
<a class="dropdown-item" href="Functions.html"> A.5. Functions and Scope</a>
|
||
<a class="dropdown-item" href="Pointers.html"> A.6. Pointers and Dynamic Allocation</a>
|
||
<a class="dropdown-item" href="Strings.html"> A.7. Strings</a>
|
||
<a class="dropdown-item" href="FunctionPointers.html"> A.8. Function Pointers</a>
|
||
<a class="dropdown-item" href="Files.html"> 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">
|
||
«  <a id="prevmod" href="Barriers.html">7.5. Barriers</a>
|
||
  ::  
|
||
<a class="uplink" href="index.html">Contents</a>
|
||
  ::  
|
||
<a id="nextmod" href="Deadlock.html">7.7. Deadlock</a>  »
|
||
|
||
</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 – <pthread.h></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">"shutdown"</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">-></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">"Enter a string/number (or shutdown to quit): "</span><span class="p">);</span>
|
||
<span class="n">memset</span> <span class="p">(</span><span class="n">args</span><span class="o">-></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">-></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 "shutdown" */</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">-></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">-></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">-></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">-></span><span class="n">buffer</span><span class="p">,</span> <span class="s">"shutdown"</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">-></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">-></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">-></span><span class="n">input_processed_cond</span><span class="p">,</span> <span class="n">args</span><span class="o">-></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">-></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">-></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">-></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">-></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">-></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">-></span><span class="n">input_cond</span><span class="p">,</span> <span class="n">args</span><span class="o">-></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">-></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">-></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">-></span><span class="n">buffer</span><span class="p">,</span> <span class="sc">'\n'</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">'\0'</span><span class="p">;</span>
|
||
<span class="n">args</span><span class="o">-></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">-></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">'\n'</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">-></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">-></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">-></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">-></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">-></span><span class="n">input_cond</span><span class="p">,</span> <span class="n">args</span><span class="o">-></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">-></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">-></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">-></span><span class="n">counter</span> <span class="o">+=</span> <span class="n">args</span><span class="o">-></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">-></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">-></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">-></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">&</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">&</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">&</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">&</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">&</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">&</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">&</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">&</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">&</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">&</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">&</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">&</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">"Total: %d</span><span class="se">\n</span><span class="s">"</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">&</span><span class="n">mutex</span><span class="p">);</span>
|
||
<span class="n">pthread_cond_destroy</span> <span class="p">(</span><span class="o">&</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">&</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 monitor’s 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 variable’s 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&localMode=true&module=Condvars&JXOP-debug=true&JOP-lang=en&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">
|
||
«  <a id="prevmod1" href="Barriers.html">7.5. Barriers</a>
|
||
  ::  
|
||
<a class="uplink" href="index.html">Contents</a>
|
||
  ::  
|
||
<a id="nextmod1" href="Deadlock.html">7.7. Deadlock</a>  »
|
||
</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> |