785 lines
No EOL
51 KiB
HTML
785 lines
No EOL
51 KiB
HTML
|
||
<!DOCTYPE html>
|
||
|
||
|
||
|
||
|
||
<html lang="en">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||
|
||
<title>7.4. Semaphores — 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="5. Barriers" href="Barriers.html" />
|
||
<link rel="prev" title="3. Locks" href="Locks.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="Semaphores.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="Semaphores.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/Semaphores.rst"
|
||
target="_blank" rel="nofollow">Show Source</a></li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
|
||
<div class="container center">
|
||
«  <a id="prevmod" href="Locks.html">7.3. Locks</a>
|
||
  ::  
|
||
<a class="uplink" href="index.html">Contents</a>
|
||
  ::  
|
||
<a id="nextmod" href="Barriers.html">7.5. Barriers</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 = "Semaphores";ODSA.SETTINGS.MODULE_LONG_NAME = "Semaphores";ODSA.SETTINGS.MODULE_CHAPTER = "Synchronization Primitives"; ODSA.SETTINGS.BUILD_DATE = "2021-06-14 14:28:48"; ODSA.SETTINGS.BUILD_CMAP = false;JSAV_OPTIONS['lang']='en';JSAV_EXERCISE_OPTIONS['code']='java';</script><div class="section" id="id1">
|
||
<h1>7.4. Semaphores<a class="headerlink" href="Semaphores.html#id1" title="Permalink to this headline">¶</a></h1>
|
||
<p><a class="reference internal" href="Glossary.html#term-semaphore"><span class="xref std std-term">Semaphores</span></a> are a flexible synchronization primitive that can
|
||
be used for many purposes. They can be used as a form of message-passing IPC to
|
||
allow processes to synchronize access to shared memory or memory-mapped files.
|
||
But in contrast to other forms of IPC, semaphores can be used for thread
|
||
synchronization, as well.</p>
|
||
<p>As described previously, a semaphore is a non-negative integer with atomic
|
||
operations for incrementing and decrementing its value. The POSIX function for
|
||
decrementing the semaphore is <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code>, while the <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code> function
|
||
increments the value. If the semaphore’s value is 0 prior to decrementing, then
|
||
the <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> operation will block the current thread. If a thread calls
|
||
<code class="docutils literal notranslate"><span class="pre">sem_post()</span></code> and there is at least one thread waiting on the semaphore, then
|
||
one of the threads becomes unblocked. The choice of which thread gets unblocked
|
||
is implementation dependent.</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 – <semaphore.h></p><hr class="mt-1" />
|
||
<dl class="docutils">
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">sem_wait</span> <span class="pre">(sem_t</span> <span class="pre">*sem);</span></code></dt>
|
||
<dd>Decrement the semaphore’s value; block if the value is currently 0.</dd>
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">sem_post</span> <span class="pre">(sem_t</span> <span class="pre">*sem);</span></code></dt>
|
||
<dd>Increment the semaphore’s value; resume another process if the value is 0.</dd>
|
||
</dl>
|
||
</div>
|
||
<p>In this section, we’ll describe three basic techniques of using semaphores:
|
||
signaling, mutual exclusion, and multiplexing. In essence, all of these
|
||
techniques look identical, but with one exception: the initial value. For
|
||
signaling, the semaphore is initialized to 0; for mutual exclusion, the initial
|
||
value is 1; for multiplexing, the initial value is a positive number greater
|
||
than 1. To summarize, the general practice is that <strong>the initial value of the
|
||
semaphore is the desired number of initial allowed concurrent accesses</strong>.</p>
|
||
<div class="section" id="semaphores-as-signaling">
|
||
<h2>7.4.1. Semaphores as Signaling<a class="headerlink" href="Semaphores.html#semaphores-as-signaling" title="Permalink to this headline">¶</a></h2>
|
||
<p>Semaphores can be used to send general signals to other threads that some
|
||
application-specific event has occurred. Note that this use of semaphores is
|
||
different from the pre-defined <a class="reference internal" href="Glossary.html#term-signal"><span class="xref std std-term">signals</span></a> such as <code class="docutils literal notranslate"><span class="pre">SIGKILL</span></code>.
|
||
Events with semaphores have no pre-defined meaning and are simply indications
|
||
that <em>something</em> has occurred.</p>
|
||
<p>To illustrate signaling, consider the two threads shown in <a class="reference external" href="Semaphores.html#cl7-7">Code Listing 7.7</a>. One thread (<code class="docutils literal notranslate"><span class="pre">keyboard_listener()</span></code>) reads a line of input from
|
||
<code class="docutils literal notranslate"><span class="pre">STDIN</span></code> into a shared buffer. Once the input has been received, the thread
|
||
posts to the semaphore to alert the second thread that the event (receiving
|
||
input) has occurred. The second thread (<code class="docutils literal notranslate"><span class="pre">keyboard_echo()</span></code>) starts by waiting
|
||
on the semaphore before trying to read the input from the buffer. The semaphore
|
||
ensures that the echo thread cannot try to read from the buffer until the
|
||
listener has finished writing to the buffer.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl7-7"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 7.7:</span>
|
||
<span class="cm"> Two threads cooperating to echo input text</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="cm">/* Struct instance will contain pointers to semaphore and buffer */</span>
|
||
<span class="k">struct</span> <span class="n">args</span> <span class="p">{</span>
|
||
<span class="n">sem_t</span> <span class="o">*</span><span class="n">semaphore</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="p">};</span>
|
||
|
||
<span class="cp">#define MAX_LENGTH 40</span>
|
||
|
||
<span class="cm">/* Listener thread gets input, then ups the semaphore */</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="cm">/* Cast the args to a usable struct type */</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="n">printf</span> <span class="p">(</span><span class="s">"Enter your name here: "</span><span class="p">);</span>
|
||
<span class="n">assert</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="cm">/* After receiving input, up the semaphore and exit */</span>
|
||
<span class="n">sem_post</span> <span class="p">(</span><span class="n">args</span><span class="o">-></span><span class="n">semaphore</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">keyboard_echo</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="cm">/* Cast the args to a usable struct type */</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">/* Wait on the signal from the semaphore */</span>
|
||
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">args</span><span class="o">-></span><span class="n">semaphore</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Trim off at the newline character */</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="cm">/* Echo back the name and exit */</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"Hello, %s</span><span class="se">\n</span><span class="s">"</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">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>The key with signaling is that the semaphore must be created and initialized
|
||
with an initial value of 0 as shown in <a class="reference external" href="Semaphores.html#cl7-8">Code Listing 7.8</a>. By using
|
||
this initial value, the semaphore eliminates the issue of nondeterministic
|
||
thread scheduling. Specifically, if the <code class="docutils literal notranslate"><span class="pre">keyboard_echo()</span></code> thread runs first,
|
||
it must wait until the <code class="docutils literal notranslate"><span class="pre">keyboard_listener()</span></code> reads the input and ups the
|
||
semaphore. However, if <code class="docutils literal notranslate"><span class="pre">keyboard_listener()</span></code> runs first and ups the semaphore
|
||
before <code class="docutils literal notranslate"><span class="pre">keyboard_echo()</span></code> gets scheduled, then the semaphore will have a value
|
||
of 1 and the thread will not be blocked.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl7-8"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 7.8:</span>
|
||
<span class="cm"> Initializing a semaphore and passing it to threads</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="cm">/* Allocate the buffer and open the named semaphore */</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="n">memset</span> <span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">buffer</span><span class="p">));</span>
|
||
|
||
<span class="cm">/* For signaling, initialize the semaphore to 0 */</span>
|
||
<span class="n">sem_t</span> <span class="o">*</span><span class="n">sem</span> <span class="o">=</span> <span class="n">sem_open</span> <span class="p">(</span><span class="s">"/OpenCSF_Sema"</span><span class="p">,</span> <span class="n">O_CREAT</span> <span class="o">|</span> <span class="n">O_EXCL</span><span class="p">,</span>
|
||
<span class="n">S_IRUSR</span> <span class="o">|</span> <span class="n">S_IWUSR</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
|
||
<span class="n">assert</span> <span class="p">(</span><span class="n">sem</span> <span class="o">!=</span> <span class="n">SEM_FAILED</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Set up struct instance with both pointers; pass it to threads */</span>
|
||
<span class="k">struct</span> <span class="n">args</span> <span class="n">args</span> <span class="o">=</span> <span class="p">{</span> <span class="n">sem</span><span class="p">,</span> <span class="n">buffer</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">0</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">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">keyboard_echo</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="cm">/* Wait for both threads to finish, then unlink the semaphore */</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">sem_unlink</span> <span class="p">(</span><span class="s">"/OpenCSF_Sema"</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>In this basic signaling pattern, it is possible to have the two threads
|
||
repeatedly post to or wait on a single semaphore. This approach is a common
|
||
technique for handling repeated events. However, it is fraught with peril. In
|
||
this example, there is only one buffer. So if the <code class="docutils literal notranslate"><span class="pre">keyboard_listener()</span></code>
|
||
repeatedly reads input (posting each time), the buffer would be repeatedly
|
||
overwritten, and there is no guarantee that the <code class="docutils literal notranslate"><span class="pre">keyboard_echo()</span></code> thread
|
||
would read any of the input.</p>
|
||
<p>Another complication arises if there are multiple threads repeatedly waiting on
|
||
the same semaphore. In the default implementation of POSIX semaphores, the
|
||
order in which threads are unblocked with <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code> is unspecified. As
|
||
such, it is possible that one thread might be repeatedly unblocked while the
|
||
other waiting thread is never unblocked.</p>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="mutual-exclusion-with-semaphores">
|
||
<h2>7.4.2. Mutual Exclusion with Semaphores<a class="headerlink" href="Semaphores.html#mutual-exclusion-with-semaphores" title="Permalink to this headline">¶</a></h2>
|
||
<p>Semaphores can also be used to ensure mutually exclusive access to a shared
|
||
variable or resource. Consider the two threads, shown in <a class="reference external" href="Semaphores.html#cl7-9">Code Listing 7.9</a>, that atomically increment or decrement an int counter variable. Each
|
||
change to the shared variable is preceded by a call to <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> and
|
||
followed by a call to <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code>. This wrapping is analogous to the mutual
|
||
exclusion style used with locks.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl7-9"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 7.9:</span>
|
||
<span class="cm"> Two threads that synchronize modifications to a shared variable</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="cm">/* Struct containing the semaphore and integer */</span>
|
||
<span class="k">struct</span> <span class="n">args</span> <span class="p">{</span>
|
||
<span class="n">sem_t</span> <span class="o">*</span><span class="n">semaphore</span><span class="p">;</span>
|
||
<span class="kt">int</span> <span class="n">value</span><span class="p">;</span>
|
||
<span class="p">};</span>
|
||
|
||
<span class="cm">/* Adder thread that repeatedly adds 10 */</span>
|
||
<span class="kt">void</span> <span class="o">*</span>
|
||
<span class="nf">add</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="cm">/* Cast the args to a usable struct type */</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="kt">int</span> <span class="n">i</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* Atomically add 10 to value 100000 times */</span>
|
||
<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="mi">100000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">args</span><span class="o">-></span><span class="n">semaphore</span><span class="p">);</span>
|
||
<span class="n">args</span><span class="o">-></span><span class="n">value</span> <span class="o">+=</span> <span class="mi">10</span><span class="p">;</span>
|
||
<span class="n">sem_post</span> <span class="p">(</span><span class="n">args</span><span class="o">-></span><span class="n">semaphore</span><span class="p">);</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="cm">/* Subtracter thread that repeatedly subtracts 10 */</span>
|
||
<span class="kt">void</span> <span class="o">*</span>
|
||
<span class="nf">subtract</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="cm">/* Cast the args to a usable struct type */</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="kt">int</span> <span class="n">i</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* Atomically subtract 10 from value 100000 times */</span>
|
||
<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="mi">100000</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">args</span><span class="o">-></span><span class="n">semaphore</span><span class="p">);</span>
|
||
<span class="n">args</span><span class="o">-></span><span class="n">value</span> <span class="o">-=</span> <span class="mi">10</span><span class="p">;</span>
|
||
<span class="n">sem_post</span> <span class="p">(</span><span class="n">args</span><span class="o">-></span><span class="n">semaphore</span><span class="p">);</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>As shown in <a class="reference external" href="Semaphores.html#cl7-10">Code Listing 7.10</a>, the difference between signaling and
|
||
mutual exclusion is the initial value of the semaphore. For mutual exclusion,
|
||
the semaphore is initialized to 1.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl7-10"><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="cm">/* Code Listing 7.10:</span>
|
||
<span class="cm"> Initializing a semaphore for mutual exclusion instead of signaling</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="cm">/* For mutual exclusion, initialize the semaphore to 1 */</span>
|
||
<span class="n">sem_t</span> <span class="o">*</span><span class="n">sem</span> <span class="o">=</span> <span class="n">sem_open</span> <span class="p">(</span><span class="s">"/OpenCSF_Sema"</span><span class="p">,</span> <span class="n">O_CREAT</span> <span class="o">|</span> <span class="n">O_EXCL</span><span class="p">,</span>
|
||
<span class="n">S_IRUSR</span> <span class="o">|</span> <span class="n">S_IWUSR</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
|
||
<span class="n">assert</span> <span class="p">(</span><span class="n">sem</span> <span class="o">!=</span> <span class="n">SEM_FAILED</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Set up a struct instance with semaphore and initial value 0 */</span>
|
||
<span class="k">struct</span> <span class="n">args</span> <span class="n">args</span> <span class="o">=</span> <span class="p">{</span> <span class="n">sem</span><span class="p">,</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">0</span><span class="p">],</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">add</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">subtract</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>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>As illustrated in <a class="reference external" href="Semaphores.html#cl7-9">Code Listing 7.9</a>, semaphores can be used
|
||
identically to mutex locks as shown previously. In fact, <a class="reference external" href="Semaphores.html#cl7-11">Code Listing 7.11</a> shows that we can use semaphores as a foundation to create locks.
|
||
Acquiring the lock involves waiting on the semaphore and setting oneself as the
|
||
lock owner. Releasing the lock clears the ownership field and posts to the
|
||
semaphore. If multiple threads try to acquire the lock, they all end up trying
|
||
to down the semaphore, and only one is successful. Once that thread releases the
|
||
lock, the semaphore is upped and a single thread is unblocked; that thread then
|
||
sets itself as the owner.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl7-11"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 7.11:</span>
|
||
<span class="cm"> Creating locks from semaphores</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="cm">/* We can create a lock with a semaphore and owner field */</span>
|
||
<span class="k">typedef</span> <span class="k">struct</span> <span class="n">lock</span> <span class="p">{</span>
|
||
<span class="n">sem_t</span> <span class="o">*</span><span class="n">semaphore</span><span class="p">;</span>
|
||
<span class="n">pthread_t</span> <span class="n">owner</span><span class="p">;</span>
|
||
<span class="p">}</span> <span class="n">lock_t</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* To acquire the lock, wait on semaphore and set self as owner */</span>
|
||
<span class="kt">int</span>
|
||
<span class="nf">mutex_lock</span> <span class="p">(</span><span class="n">lock_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="kt">int</span> <span class="n">retvalue</span> <span class="o">=</span> <span class="n">sem_wait</span> <span class="p">(</span><span class="n">lock</span><span class="o">-></span><span class="n">semaphore</span><span class="p">);</span>
|
||
<span class="n">lock</span><span class="o">-></span><span class="n">owner</span> <span class="o">=</span> <span class="n">pthread_self</span> <span class="p">();</span>
|
||
<span class="k">return</span> <span class="n">retvalue</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="cm">/* To release, clear the owner field and post to the semaphore */</span>
|
||
<span class="kt">int</span>
|
||
<span class="nf">mutex_unlock</span> <span class="p">(</span><span class="n">lock_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="cm">/* Only the owner can release the lock */</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">lock</span><span class="o">-></span><span class="n">owner</span> <span class="o">!=</span> <span class="n">pthread_self</span> <span class="p">())</span>
|
||
<span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
|
||
<span class="n">lock</span><span class="o">-></span><span class="n">owner</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
|
||
<span class="k">return</span> <span class="n">sem_post</span> <span class="p">(</span><span class="n">lock</span><span class="o">-></span><span class="n">semaphore</span><span class="p">);</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>The key difference between locks and semaphores is that a semaphore must be
|
||
explicitly initialized to the integer value 1, whereas the initialization for a
|
||
lock is opaque. Or, put a different way, <strong>mutex locks are preferred because
|
||
they adhere to the principles of encapsulation and information hiding</strong>. The
|
||
notion of <em>acquiring a lock</em> is more concrete than <em>waiting on a semaphore,</em> and
|
||
is a more appropriate abstraction for mutual exclusion.</p>
|
||
</div>
|
||
<div class="section" id="multiplexing-with-semaphores">
|
||
<h2>7.4.3. Multiplexing with Semaphores<a class="headerlink" href="Semaphores.html#multiplexing-with-semaphores" title="Permalink to this headline">¶</a></h2>
|
||
<p>Both locks and semaphores can be used for mutual exclusion, though locks are
|
||
typically the preferred abstraction. However, the mutual exclusion style of
|
||
semaphores can be extended to allow for multiple but limited shared accesses.
|
||
This concept is known as <a class="reference internal" href="Glossary.html#term-multiplexing-semaphore"><span class="xref std std-term">multiplexing</span></a>. That is, while a lock can only be
|
||
used to grant access to a single thread at a time, a semaphore can be set to
|
||
allow 5, 10, or any other number of concurrent accesses. Once this limited
|
||
number has been reached, any additional threads would become blocked, just as
|
||
they would if trying to acquire a locked mutex.</p>
|
||
<p>As a real-world example of multiplexing, consider a popular restaurant or club.
|
||
Building safety codes specify that there is a maximum occupancy, say 100 people.
|
||
As patrons start arriving when the place opens, they are allowed in one at a
|
||
time. However, once the 100th person has been allowed in, the management must
|
||
make sure that no one else enters (or risk legal trouble and fines). At that
|
||
point, a line forms out front. Once a single person leaves, the next patron is
|
||
allowed in. In this case, <strong>the employee enforcing this restriction at the
|
||
entrance is acting like a multiplexing semaphore with an initial value of 100</strong>.</p>
|
||
<p>Within the context of computing, multiplexing has many uses. One example is to
|
||
limit the number of concurrent accesses to a pool of resources where more than
|
||
one is required for each operation. For example, consider a networking hub that
|
||
has 10 incoming ports and 10 outgoing ports that can be locked independently.
|
||
Consider the scenario where 9 threads have already locked both an incoming and
|
||
an outgoing port. Two new threads arrive; one of them acquires an incoming port
|
||
and the second acquires an outgoing port. At this point, no ports of either kind
|
||
are available. If these last two threads then try to acquire the missing port,
|
||
they cannot. As a result, there are two ports (one incoming and one outgoing)
|
||
that are both locked but not in use. This waste of resources could be prevented
|
||
with the structure in <a class="reference external" href="Semaphores.html#cl7-12">Code Listing 7.12</a>.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl7-12"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 7.12:</span>
|
||
<span class="cm"> Using a semaphore to multiplex access to a thread pool</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="cm">/* Acquire access to the pool of resources */</span>
|
||
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">pool_semaphore</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Try to acquire incoming port. If taken, move on to the next. */</span>
|
||
<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="mi">10</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">pthread_mutex_trylock</span> <span class="p">(</span><span class="n">incoming_mutex</span><span class="p">[</span><span class="n">i</span><span class="p">]))</span>
|
||
<span class="p">{</span>
|
||
<span class="n">in</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
|
||
<span class="k">break</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="cm">/* Work with incoming port, even if no outgoing port is needed */</span>
|
||
|
||
<span class="cm">/* Once an outgoing port is needed, acquire it in the same way. */</span>
|
||
<span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="mi">10</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">pthread_mutex_trylock</span> <span class="p">(</span><span class="n">outgoing_mutex</span><span class="p">[</span><span class="n">i</span><span class="p">]))</span>
|
||
<span class="p">{</span>
|
||
<span class="n">out</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span>
|
||
<span class="k">break</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="cm">/* To finish, release both locks and up the semaphore */</span>
|
||
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">incoming_mutex</span><span class="p">[</span><span class="n">in</span><span class="p">]);</span>
|
||
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">outgoing_mutex</span><span class="p">[</span><span class="n">out</span><span class="p">]);</span>
|
||
<span class="n">sem_post</span> <span class="p">(</span><span class="n">pool_semaphore</span><span class="p">);</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>Assuming the <code class="docutils literal notranslate"><span class="pre">pool_semaphore</span></code> was initialized to 10, every thread granted
|
||
access to the pool of resources (ports in this example) will have access to one
|
||
of each type. Moreover, this structure makes it possible for the incoming and
|
||
outgoing ports to be acquired in any order; this flexibility is commonly
|
||
associated with the problem of <a class="reference internal" href="Glossary.html#term-deadlock"><span class="xref std std-term">deadlock</span></a>, but multiplexing in this manner
|
||
avoids that issue.</p>
|
||
<div
|
||
id="SynchSemsSumm"
|
||
class="embedContainer"
|
||
data-exer-name="SynchSemsSumm"
|
||
data-long-name="Semaphore questions"
|
||
data-short-name="SynchSemsSumm"
|
||
data-frame-src="../../../Exercises/Synch/SynchSemsSumm.html?selfLoggingEnabled=false&localMode=true&module=Semaphores&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="3"
|
||
data-type="ka"
|
||
data-exer-id="">
|
||
|
||
<div class="center">
|
||
<div id="SynchSemsSumm_iframe"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<div class="container">
|
||
|
||
<div class="mt-4 container center">
|
||
«  <a id="prevmod1" href="Locks.html">7.3. Locks</a>
|
||
  ::  
|
||
<a class="uplink" href="index.html">Contents</a>
|
||
  ::  
|
||
<a id="nextmod1" href="Barriers.html">7.5. Barriers</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> |