903 lines
61 KiB
HTML
903 lines
61 KiB
HTML
|
|
|||
|
<!DOCTYPE html>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<html lang="en">
|
|||
|
<head>
|
|||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|||
|
|
|||
|
<title>8.2. Basic Synchronization Design Patterns — 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="3. Producer-Consumer Problem" href="ProdCons.html" />
|
|||
|
<link rel="prev" title="1. Synchronization Patterns and Problems" href="SynchProblemsOverview.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="SynchDesign.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="SynchDesign.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/SynchDesign.rst"
|
|||
|
target="_blank" rel="nofollow">Show Source</a></li>
|
|||
|
|
|||
|
</ul>
|
|||
|
</nav>
|
|||
|
|
|||
|
|
|||
|
<div class="container center">
|
|||
|
«  <a id="prevmod" href="SynchProblemsOverview.html">8.1. Synchronization Patterns and Problems</a>
|
|||
|
  ::  
|
|||
|
<a class="uplink" href="index.html">Contents</a>
|
|||
|
  ::  
|
|||
|
<a id="nextmod" href="ProdCons.html">8.3. Producer-Consumer Problem</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 = "SynchDesign";ODSA.SETTINGS.MODULE_LONG_NAME = "Basic Synchronization Design Patterns";ODSA.SETTINGS.MODULE_CHAPTER = "Synchronization Patterns and Problems"; 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="basic-synchronization-design-patterns">
|
|||
|
<h1>8.2. Basic Synchronization Design Patterns<a class="headerlink" href="SynchDesign.html#basic-synchronization-design-patterns" title="Permalink to this headline">¶</a></h1>
|
|||
|
<p><a class="reference internal" href="Glossary.html#term-lock"><span class="xref std std-term">Locks</span></a> are very simple synchronization primitives, as they have
|
|||
|
only one intended purpose: ensuring mutually exclusive access to a critical
|
|||
|
section. Other primitives, such as <a class="reference internal" href="Glossary.html#term-semaphore"><span class="xref std std-term">semaphores</span></a>, can also
|
|||
|
provide mutual exclusion. However, semaphores are flexible and can be used for a
|
|||
|
variety of synchronization goals. This section describes four common techniques.</p>
|
|||
|
<div class="section" id="signaling">
|
|||
|
<h2>8.2.1. Signaling<a class="headerlink" href="SynchDesign.html#signaling" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>The simplest synchronization design pattern uses semaphores for <a class="reference internal" href="Glossary.html#term-signaling-synchronization"><span class="xref std std-term">signaling</span></a>.
|
|||
|
Signaling arises when one thread needs to wait until some particular event has
|
|||
|
occurred. This timing is accomplished by waiting on shared semaphore that is
|
|||
|
incremented immediately after the event.</p>
|
|||
|
<blockquote>
|
|||
|
<div><ul class="simple">
|
|||
|
<li>Initialize the semaphore to 0.</li>
|
|||
|
<li>One thread calls <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> to block until some critical event has occurred.</li>
|
|||
|
<li>A second thread detects that the event has occurred, then calls <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code> to
|
|||
|
unblock the waiting thread.</li>
|
|||
|
</ul>
|
|||
|
</div></blockquote>
|
|||
|
<p>The key observation with signaling is that the scheduling of the threads does
|
|||
|
not affect the correctness of the results. That is, there are only two possible
|
|||
|
scenarios to consider. In one scenario, the thread that calls <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code>
|
|||
|
runs first. Since the semaphore is initialized to 0, the thread must block until
|
|||
|
the other thread runs and calls <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code>. Alternatively, the second thread
|
|||
|
runs first and calls <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code>, incrementing the semaphore’s value to 1.
|
|||
|
Then, when the other thread calls <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code>, it can proceed without
|
|||
|
blocking because the event has already occurred.</p>
|
|||
|
<p><a class="reference external" href="SynchDesign.html#cl8-1">Code Listing 8.1</a> uses a separate thread to perform some sort of
|
|||
|
initialization work. For instance, this initialization might involve reading in
|
|||
|
a large amount of data from configuration files, allocating request queues,
|
|||
|
overwriting the default signal handlers, or other such tasks. This
|
|||
|
initialization may be done concurrently with other work that the main thread is
|
|||
|
trying to accomplish. But at a certain point, the main thread needs to pause
|
|||
|
until it can be guaranteed that all of the initialization is done. The semaphore
|
|||
|
guarantees the timing of this pause.</p>
|
|||
|
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-1"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.1:</span>
|
|||
|
<span class="cm"> The general structure of a program that uses signaling after initialization</span>
|
|||
|
<span class="cm"> */</span>
|
|||
|
|
|||
|
<span class="kt">void</span> <span class="o">*</span>
|
|||
|
<span class="nf">initialize</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 arguments into a useful struct type */</span>
|
|||
|
<span class="n">sem_t</span> <span class="o">*</span><span class="n">semaphore</span> <span class="o">=</span> <span class="p">(</span><span class="n">sem_t</span> <span class="o">*</span><span class="p">)</span> <span class="n">args</span><span class="p">;</span>
|
|||
|
<span class="cm">/* Perform some time-consuming initialization here */</span>
|
|||
|
<span class="cm">/* Alert calculate thread that initialization is complete */</span>
|
|||
|
<span class="n">sem_post</span> <span class="p">(</span><span class="n">semaphore</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Perform some clean-up or do other work before exiting */</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">int</span>
|
|||
|
<span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="cm">/* Declarations omitted for brevity */</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">init_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">init_sem</span> <span class="o">!=</span> <span class="n">SEM_FAILED</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Create initialization thread */</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">init</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">initialize</span><span class="p">,</span> <span class="n">init_sem</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Perform other work while initialization occurs */</span>
|
|||
|
<span class="cm">/* Pause until initialization is complete */</span>
|
|||
|
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">init_sem</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>
|
|||
|
<span class="cm">/* Do other work that depended on complete initialization */</span>
|
|||
|
<span class="k">return</span> <span class="n">EXIT_SUCCESS</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</pre></div>
|
|||
|
</td></tr></table></div>
|
|||
|
<p>The use of the semaphore here may seem unnecessary, and that would be a fair
|
|||
|
objection to this particular scenario. That is, the same timing could be
|
|||
|
achieved by having the main thread call <code class="docutils literal notranslate"><span class="pre">pthread_join()</span></code> when it needs to wait
|
|||
|
for the initialization thread to complete. However, using the semaphore allows
|
|||
|
the initialization thread to signal that the critical work has been done
|
|||
|
<em>before</em> the thread finishes. This early notification may be beneficial if the
|
|||
|
thread needs to perform additional work, such as freeing up allocated memory or
|
|||
|
cleaning up files. Furthermore, there may be other threads that are also waiting
|
|||
|
on the initialization; since they are not the thread’s parent, they cannot join
|
|||
|
it and must be signaled using a mechanism such as a semaphore.</p>
|
|||
|
</div>
|
|||
|
<div class="section" id="turnstiles">
|
|||
|
<h2>8.2.2. Turnstiles<a class="headerlink" href="SynchDesign.html#turnstiles" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>A <a class="reference internal" href="Glossary.html#term-turnstile"><span class="xref std std-term">turnstile</span></a> is a variant on signaling that can cause a chain-reaction
|
|||
|
that unblocks several threads one at a time. The key structure of a turnstile is
|
|||
|
to follow <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> immediately with a call to <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code>. As with
|
|||
|
signaling, the semaphore must be initialized to 0, which ensures that every
|
|||
|
thread executing the turnstile gets blocked. That is, the turnstile acts like a
|
|||
|
locked door and the threads form a queue waiting to get in.</p>
|
|||
|
<p>Once it becomes acceptable for the threads to enter, one thread makes a single
|
|||
|
call to <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code>. This call unblocks exactly one thread that is waiting at
|
|||
|
the turnstile; that thread returns from the <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> that had blocked it
|
|||
|
and immediately calls <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code>, unblocking the next thread. This pattern
|
|||
|
then continues, with each thread unblocking the next thread in line, one at a
|
|||
|
time. <a class="reference external" href="SynchDesign.html#cl8-2">Code Listing 8.2</a> illustrates this pattern, with the <code class="docutils literal notranslate"><span class="pre">user()</span></code>
|
|||
|
waiting at the turnstile.</p>
|
|||
|
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-2"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.2:</span>
|
|||
|
<span class="cm"> Turnstiles create a sequence of unblocking all other threads</span>
|
|||
|
<span class="cm"> */</span>
|
|||
|
|
|||
|
<span class="kt">void</span> <span class="o">*</span>
|
|||
|
<span class="nf">user</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="n">sem_t</span> <span class="o">*</span><span class="n">semaphore</span> <span class="o">=</span> <span class="p">(</span><span class="n">sem_t</span> <span class="o">*</span><span class="p">)</span> <span class="n">args</span><span class="p">;</span>
|
|||
|
|
|||
|
<span class="cm">/* Turnstile causes a chain reaction of unblocking */</span>
|
|||
|
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">semaphore</span><span class="p">);</span>
|
|||
|
<span class="n">sem_post</span> <span class="p">(</span><span class="n">semaphore</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Do other work and exit the thread */</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
<span class="kt">int</span>
|
|||
|
<span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="cm">/* Declarations and earlier work */</span>
|
|||
|
<span class="cm">/* Create helper threads */</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="n">NUM_THREADS</span><span class="p">;</span> <span class="n">i</span><span class="o">++</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="kr">thread</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">user</span><span class="p">,</span> <span class="n">sem</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Unblock the first thread, which unblocks the second, etc. */</span>
|
|||
|
<span class="n">sem_post</span> <span class="p">(</span><span class="n">sem</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Continue with other work */</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</pre></div>
|
|||
|
</td></tr></table></div>
|
|||
|
<p>Turnstiles allow POSIX semaphores to behave similar to the broadcast feature of
|
|||
|
<a class="reference internal" href="Glossary.html#term-condition-variable"><span class="xref std std-term">condition variables</span></a> or using the System V
|
|||
|
<code class="docutils literal notranslate"><span class="pre">semop()</span></code> function to increase a semaphore by more than 1. There is a key
|
|||
|
difference that distinguishes the intended use of turnstiles, though. Turnstiles
|
|||
|
cause the unblocking to propagate to all threads that are waiting at the
|
|||
|
turnstile, but also those that have not arrived yet. Broadcasting only notifies
|
|||
|
threads that are already waiting, and <code class="docutils literal notranslate"><span class="pre">semop()</span></code> unblocks a maximum of the
|
|||
|
number of threads specified by the <code class="docutils literal notranslate"><span class="pre">sem_op</span></code> argument. In other words,
|
|||
|
turnstiles permanently unblock all current and future threads based on a key event.</p>
|
|||
|
</div>
|
|||
|
<div class="section" id="rendezvous">
|
|||
|
<h2>8.2.3. Rendezvous<a class="headerlink" href="SynchDesign.html#rendezvous" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>A <a class="reference internal" href="Glossary.html#term-rendezvous"><span class="xref std std-term">rendezvous</span></a> is a mutual signaling between two threads. The goal of a rendezvous is to ensure that two threads meet at a pre-defined common point. To create a rendezvous, two semaphores are initialized to 0. The two threads then call <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code> on one semaphore just prior to calling <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> on the other. At run-time, one thread will arrive at the rendezvous first and get blocked by the call to <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code>. Then, when the other thread arrives, it unblocks the first by calling <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code>; however, this thread is not blocked by the call to <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code>, as the semaphore’s value has already been incremented to 1.</p>
|
|||
|
<p>To illustrate the use of a rendezvous, assume that a program wants to detect corrupted files on a web server. To do this, the program uses one thread to retrieve the file from the web site; a second thread reads the same file from a location that is known to be secure and correct. The two threads need to complete reading the two copies before comparing their contents (a mismatch would indicate corruption). <a class="reference external" href="SynchDesign.html#cl8-3">Code Listing 8.3</a> shows the structure for these two threads.</p>
|
|||
|
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-3"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.3:</span>
|
|||
|
<span class="cm"> Separate threads can be used to download a file twice to detect corruption</span>
|
|||
|
<span class="cm"> */</span>
|
|||
|
|
|||
|
<span class="kt">void</span> <span class="o">*</span>
|
|||
|
<span class="nf">download</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 arguments into a useful 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">/* Download the file from the potentially corrupted server */</span>
|
|||
|
<span class="cm">/* Rendezvous; must wait until secure loading is done */</span>
|
|||
|
<span class="n">sem_post</span> <span class="p">(</span><span class="n">args</span><span class="o">-></span><span class="n">download_sem</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">secure_sem</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Additional work or thread cleanup here */</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
<span class="kt">void</span> <span class="o">*</span>
|
|||
|
<span class="nf">secure_load</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">/* Securely load the file from a correct location */</span>
|
|||
|
<span class="cm">/* Rendezvous; must wait until downloading is done */</span>
|
|||
|
<span class="n">sem_post</span> <span class="p">(</span><span class="n">args</span><span class="o">-></span><span class="n">secure_sem</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">download_sem</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Additional work or thread cleanup here */</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</pre></div>
|
|||
|
</td></tr></table></div>
|
|||
|
</div>
|
|||
|
<div class="section" id="multiplexing">
|
|||
|
<h2>8.2.4. Multiplexing<a class="headerlink" href="SynchDesign.html#multiplexing" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>In many cases, mutual exclusion is too strong of a system requirement, but it is reasonable to place a limit on the number of concurrent accesses. For example, network servers (e.g., web or e-mail servers) allow hundreds or thousands of concurrent network connections to serve content to remote users. Allowing an unlimited number of connections would exhaust the system resources, such as consuming all of the system’s available memory or trying to read too many files on a single hard drive.</p>
|
|||
|
<p>The solution in this case is <a class="reference internal" href="Glossary.html#term-multiplexing-semaphore"><span class="xref std std-term">multiplexing</span></a>. Multiplexing allows multiple concurrent accesses up to a given limit; additional requests beyond that limit are blocked until more resources become available. The key defining feature of multiplexing is to initialize the semaphore’s value to a positive integer greater than 1. This initial value is the <em>maximum</em> number of concurrent accesses allowed. Once the thread semaphore has been decremented to 0, the limit has been reached and future accesses are blocked. Mutual exclusion is a special case of multiplexing, where the initial value is 1.</p>
|
|||
|
<p><a class="reference external" href="SynchDesign.html#cl8-4">Code Listing 8.4</a> illustrates the code framework for a server that launches a new thread each time a request has been received. Whenever a request is received, the main thread first decrements the semaphore to determine if the limit has been reached. If the limit has not been reached, a new thread handles the request. However, if the maximum number of threads has already been reached, the main thread gets blocked. Eventually, one of the threads serving content finishes. Just before exiting, that thread increments the semaphore, which unblocks the main thread; at that point, the main thread creates a new thread to handle the pending request it had received.</p>
|
|||
|
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-4"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.4:</span>
|
|||
|
<span class="cm"> Semaphore multiplexing can place a limit on the number of concurrent threads</span>
|
|||
|
<span class="cm"> */</span>
|
|||
|
|
|||
|
<span class="kt">void</span> <span class="o">*</span>
|
|||
|
<span class="nf">serve_content</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 struct to get the semaphore and arguments */</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">/* ... Serve content based on the request ... */</span>
|
|||
|
<span class="cm">/* Thread is exiting; post to allow more threads in */</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">int</span>
|
|||
|
<span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="cm">/* Initialization and other work */</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 for incoming request ... */</span>
|
|||
|
|
|||
|
<span class="cm">/* Request received; can a new thread be created? */</span>
|
|||
|
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">create_thread_sem</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Thread limit is not reached, so create a new thread */</span>
|
|||
|
<span class="n">args</span> <span class="o">=</span> <span class="n">malloc</span> <span class="p">(</span><span class="k">sizeof</span> <span class="p">(</span><span class="k">struct</span> <span class="n">args</span><span class="p">));</span>
|
|||
|
<span class="n">args</span><span class="o">-></span><span class="n">semaphore</span> <span class="o">=</span> <span class="n">create_thread_sem</span><span class="p">;</span>
|
|||
|
<span class="cm">/* Additional args initialization here */</span>
|
|||
|
<span class="cm">/* Create the thread; up the semaphore if creation fails */</span>
|
|||
|
<span class="k">if</span> <span class="p">(</span><span class="n">pthread_create</span> <span class="p">(</span><span class="o">&</span><span class="n">child_thread</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">serve_content</span><span class="p">,</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">sem_post</span> <span class="p">(</span><span class="n">create_thread_sem</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</pre></div>
|
|||
|
</td></tr></table></div>
|
|||
|
</div>
|
|||
|
<div class="section" id="lightswitches">
|
|||
|
<h2>8.2.5. Lightswitches<a class="headerlink" href="SynchDesign.html#lightswitches" title="Permalink to this headline">¶</a></h2>
|
|||
|
<p>When providing concurrent access to a resource, it is sometimes necessary to
|
|||
|
distinguish between the type of threads that are allowed access. For instance,
|
|||
|
consider a web-based application that allows multiple people to edit a document
|
|||
|
collaboratively. Each user is assigned a separate thread for modifying the
|
|||
|
contents of the document. In addition, a separate thread is responsible for
|
|||
|
storing a backup copy automatically. Other threads might be running to check the
|
|||
|
spelling or grammar. When there are different types of threads, it may be
|
|||
|
necessary for one type of thread to lock out other types while still allowing
|
|||
|
concurrent access for the same type.</p>
|
|||
|
<p>The <a class="reference internal" href="Glossary.html#term-lightswitch"><span class="xref std std-term">lightswitch</span></a> pattern makes it possible to enforce this type of
|
|||
|
constraint. In addition, the lightswitch allows the first thread of a particular
|
|||
|
type to perform some initialization as needed. The name derives from the idea of
|
|||
|
a group of people entering a room; the first person to enter turns on the lights
|
|||
|
by flipping the lightswitch and the last person to leave turns the lights off.
|
|||
|
<a class="reference external" href="SynchDesign.html#cl8-5">Code Listing 8.5</a> shows one variant on a lightswitch. Note that the
|
|||
|
<code class="docutils literal notranslate"><span class="pre">if</span></code> statement in both cases can be extended to perform additional
|
|||
|
initialization and clean-up work if needed.</p>
|
|||
|
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-5"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.5:</span>
|
|||
|
<span class="cm"> Functions for creating an asymmetric lightswitch</span>
|
|||
|
<span class="cm"> */</span>
|
|||
|
|
|||
|
<span class="kt">void</span>
|
|||
|
<span class="nf">enter</span> <span class="p">(</span><span class="n">pthread_mutex_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">,</span> <span class="n">sem_t</span> <span class="o">*</span><span class="n">can_enter</span><span class="p">,</span> <span class="kt">int</span> <span class="n">counter</span><span class="p">)</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
|
|||
|
<span class="cm">/* First thread waits to be able to enter */</span>
|
|||
|
<span class="k">if</span> <span class="p">(</span><span class="o">++</span><span class="n">counter</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>
|
|||
|
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">can_enter</span><span class="p">);</span>
|
|||
|
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
<span class="kt">void</span>
|
|||
|
<span class="nf">leave</span> <span class="p">(</span><span class="n">pthread_mutex_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">,</span> <span class="n">sem_t</span> <span class="o">*</span><span class="n">can_enter</span><span class="p">,</span> <span class="kt">int</span> <span class="n">counter</span><span class="p">)</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Last thread waits to be able to enter */</span>
|
|||
|
<span class="k">if</span> <span class="p">(</span><span class="o">--</span><span class="n">counter</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
|
|||
|
<span class="n">sem_post</span> <span class="p">(</span><span class="n">can_enter</span><span class="p">);</span>
|
|||
|
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">unlock</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</pre></div>
|
|||
|
</td></tr></table></div>
|
|||
|
<p>The implementation in <a class="reference external" href="SynchDesign.html#cl8-5">Code Listing 8.5</a> works for an <em>asymmetric</em>
|
|||
|
approach in which one type of thread allows concurrent access while another does
|
|||
|
not. The <code class="docutils literal notranslate"><span class="pre">enter()</span></code> and <code class="docutils literal notranslate"><span class="pre">leave()</span></code> functions would be used by the thread type
|
|||
|
that allows concurrency. The thread type that requires mutual exclusion would
|
|||
|
work directly with the <code class="docutils literal notranslate"><span class="pre">can_enter</span></code> semaphore without using the lock. That is, the
|
|||
|
lightswitch could be used as shown in <a class="reference external" href="SynchDesign.html#cl8-6">Code Listing 8.6</a>.</p>
|
|||
|
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-6"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.6:</span>
|
|||
|
<span class="cm"> Using a lightswitch in asymmetric concurrency</span>
|
|||
|
<span class="cm"> */</span>
|
|||
|
|
|||
|
<span class="kt">void</span> <span class="o">*</span>
|
|||
|
<span class="nf">concurrent_thread</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 struct to get the data fields */</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">enter</span> <span class="p">(</span><span class="n">args</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">args</span><span class="o">-></span><span class="n">can_enter</span><span class="p">,</span> <span class="n">args</span><span class="o">-></span><span class="n">counter</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Critical section for concurrent access */</span>
|
|||
|
<span class="n">leave</span> <span class="p">(</span><span class="n">args</span><span class="o">-></span><span class="n">lock</span><span class="p">,</span> <span class="n">args</span><span class="o">-></span><span class="n">can_enter</span><span class="p">,</span> <span class="n">args</span><span class="o">-></span><span class="n">counter</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Do other work and exit thread */</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
<span class="kt">void</span> <span class="o">*</span>
|
|||
|
<span class="n">mutex_thread</span> <span class="nf">thread</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 struct to get the data fields */</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">sem_wait</span> <span class="p">(</span><span class="n">args</span><span class="o">-></span><span class="n">can_enter</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Critical section for concurrent access */</span>
|
|||
|
<span class="n">sem_post</span> <span class="p">(</span><span class="n">args</span><span class="o">-></span><span class="n">can_enter</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Do other work and exit thread */</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>The lightswitch in <a class="reference external" href="SynchDesign.html#cl8-6">Code Listing 8.6</a> is not safe if all types of
|
|||
|
threads allow for concurrent access to their respective critical sections.
|
|||
|
Consider the case where a thread of type A has previously entered. After that
|
|||
|
point, a thread of type B tries to enter, but is blocked by the semaphore
|
|||
|
within the <code class="docutils literal notranslate"><span class="pre">if</span></code> statement. Note, though, that this thread still retains the
|
|||
|
lock as it gets blocked. When any type A thread tries to leave, they will get
|
|||
|
blocked trying to acquire the lock. Consequently, none of the type A threads
|
|||
|
can post to the semaphore according to the <code class="docutils literal notranslate"><span class="pre">leave()</span></code> function. The system
|
|||
|
would then enter a state of <a class="reference internal" href="Glossary.html#term-deadlock"><span class="xref std std-term">deadlock</span></a>, as the type A threads are waiting
|
|||
|
on the type B thread that has the lock while the type B thread is waiting on a
|
|||
|
type A thread to post to the semaphore.</p>
|
|||
|
</div>
|
|||
|
<p>If the concurrency is not asymmetric—that is, multiple types of threads allow
|
|||
|
concurrent access—then the <code class="docutils literal notranslate"><span class="pre">if</span></code> statement would need to be modified. Using the
|
|||
|
structure in <a class="reference external" href="SynchDesign.html#cl8-5">Code Listing 8.5</a>, the <code class="docutils literal notranslate"><span class="pre">enter()</span></code> function could be
|
|||
|
modified to release the lock prior to calling <code class="docutils literal notranslate"><span class="pre">sem_wait(can_enter)</span></code>, then
|
|||
|
re-acquiring it as shown in <a class="reference external" href="SynchDesign.html#cl8-7">Code Listing 8.7</a>. Note that the
|
|||
|
<code class="docutils literal notranslate"><span class="pre">leave()</span></code> function remains unchanged, as <code class="docutils literal notranslate"><span class="pre">sem_post(can_enter)</span></code> would
|
|||
|
never block.</p>
|
|||
|
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.7:</span>
|
|||
|
<span class="cm"> A lightswitch for concurrency of all thread types</span>
|
|||
|
<span class="cm"> */</span>
|
|||
|
|
|||
|
<span class="kt">void</span>
|
|||
|
<span class="nf">enter</span> <span class="p">(</span><span class="n">pthread_mutex_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">,</span> <span class="n">sem_t</span> <span class="o">*</span><span class="n">can_enter</span><span class="p">,</span> <span class="kt">int</span> <span class="n">counter</span><span class="p">)</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
|
|||
|
<span class="cm">/* First thread waits to be able to enter */</span>
|
|||
|
<span class="k">if</span> <span class="p">(</span><span class="o">++</span><span class="n">counter</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
|
|||
|
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">can_enter</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="k">else</span>
|
|||
|
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</pre></div>
|
|||
|
</td></tr></table></div>
|
|||
|
<p>As an alternative, the lightswitch could be modified to use condition variables
|
|||
|
as shown in <a class="reference external" href="SynchDesign.html#cl8-8">Code Listing 8.8</a>. In this case, a bool variable is added
|
|||
|
to indicate whether or not a new type of thread can enter its respective
|
|||
|
critical section. When the first thread of a new type enters the critical
|
|||
|
section, it would set <code class="docutils literal notranslate"><span class="pre">can_enter</span></code> to false, blocking out other threads that
|
|||
|
would try to enter until the last leaving thread sets <code class="docutils literal notranslate"><span class="pre">can_enter</span></code> back to true.</p>
|
|||
|
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-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
|
|||
|
25
|
|||
|
26
|
|||
|
27
|
|||
|
28
|
|||
|
29
|
|||
|
30
|
|||
|
31
|
|||
|
32</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.8:</span>
|
|||
|
<span class="cm"> Adapting the lightswitch for condition variables</span>
|
|||
|
<span class="cm"> */</span>
|
|||
|
|
|||
|
<span class="kt">void</span>
|
|||
|
<span class="nf">enter</span> <span class="p">(</span><span class="n">pthread_mutex_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">,</span> <span class="n">pthread_cond_t</span> <span class="o">*</span><span class="n">leave</span><span class="p">,</span>
|
|||
|
<span class="kt">bool</span> <span class="n">can_enter</span><span class="p">,</span> <span class="kt">int</span> <span class="n">counter</span><span class="p">)</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
|
|||
|
<span class="cm">/* First thread waits to be able to enter */</span>
|
|||
|
<span class="k">if</span> <span class="p">(</span><span class="o">++</span><span class="n">counter</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="k">while</span> <span class="p">(</span><span class="o">!</span> <span class="n">can_enter</span><span class="p">)</span>
|
|||
|
<span class="n">pthread_cond_wait</span> <span class="p">(</span><span class="n">leave</span><span class="p">,</span> <span class="n">lock</span><span class="p">);</span>
|
|||
|
<span class="n">can_enter</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
<span class="kt">void</span>
|
|||
|
<span class="nf">leave</span> <span class="p">(</span><span class="n">pthread_mutex_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">,</span> <span class="n">pthread_cond_t</span> <span class="o">*</span><span class="n">leave</span><span class="p">,</span>
|
|||
|
<span class="kt">bool</span> <span class="n">can_enter</span><span class="p">,</span> <span class="kt">int</span> <span class="n">counter</span><span class="p">)</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Last thread waits to be able to enter */</span>
|
|||
|
<span class="k">if</span> <span class="p">(</span><span class="o">--</span><span class="n">counter</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="n">can_enter</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
|
|||
|
<span class="n">pthread_cond_signal</span> <span class="p">(</span><span class="n">leave</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">unlock</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</pre></div>
|
|||
|
</td></tr></table></div>
|
|||
|
<p>Given that the lightswitch pattern is more complex than the other patterns, it
|
|||
|
is a good design choice to encapsulate the variables into a single <code class="docutils literal notranslate"><span class="pre">struct</span></code>
|
|||
|
that can then be passed around. Any thread needing access to the same
|
|||
|
lightswitch could be passed a pointer to the <code class="docutils literal notranslate"><span class="pre">struct</span></code> instance in the thread
|
|||
|
arguments as shown in <a class="reference external" href="SynchDesign.html#cl8-9">Code Listing 8.9</a>. Note that this assumes the
|
|||
|
interface for <code class="docutils literal notranslate"><span class="pre">enter()</span></code> and <code class="docutils literal notranslate"><span class="pre">leave()</span></code> have been adapted to receive the
|
|||
|
struct parameter instead of the individual fields.</p>
|
|||
|
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.9:</span>
|
|||
|
<span class="cm"> A modular approach to lightswitches</span>
|
|||
|
<span class="cm"> */</span>
|
|||
|
|
|||
|
<span class="k">typedef</span> <span class="k">struct</span> <span class="n">lightswitch</span> <span class="p">{</span>
|
|||
|
<span class="n">pthread_mutex_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">;</span>
|
|||
|
<span class="n">sem_t</span> <span class="o">*</span><span class="n">can_enter</span><span class="p">;</span>
|
|||
|
<span class="kt">int</span> <span class="n">counter</span><span class="p">;</span>
|
|||
|
<span class="p">}</span> <span class="n">ls_t</span><span class="p">;</span>
|
|||
|
|
|||
|
<span class="kt">void</span> <span class="o">*</span>
|
|||
|
<span class="nf">lightswitch_user</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 struct to get the data fields */</span>
|
|||
|
<span class="n">ls_t</span> <span class="o">*</span><span class="n">lightswitch</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">enter</span> <span class="p">(</span><span class="n">lightswitch</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Critical section */</span>
|
|||
|
<span class="n">leave</span> <span class="p">(</span><span class="n">lightswitch</span><span class="p">);</span>
|
|||
|
<span class="cm">/* Do other work and exit thread */</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</pre></div>
|
|||
|
</td></tr></table></div>
|
|||
|
<div
|
|||
|
id="SynchProbDesignSumm"
|
|||
|
class="embedContainer"
|
|||
|
data-exer-name="SynchProbDesignSumm"
|
|||
|
data-long-name="Synchronization Problem Design Patterns Summary Questions"
|
|||
|
data-short-name="SynchProbDesignSumm"
|
|||
|
data-frame-src="../../../Exercises/SynchProblems/SynchProbDesignSumm.html?selfLoggingEnabled=false&localMode=true&module=SynchDesign&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="SynchProbDesignSumm_iframe"></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<div class="container">
|
|||
|
|
|||
|
<div class="mt-4 container center">
|
|||
|
«  <a id="prevmod1" href="SynchProblemsOverview.html">8.1. Synchronization Patterns and Problems</a>
|
|||
|
  ::  
|
|||
|
<a class="uplink" href="index.html">Contents</a>
|
|||
|
  ::  
|
|||
|
<a id="nextmod1" href="ProdCons.html">8.3. Producer-Consumer Problem</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>
|