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

583 lines
No EOL
38 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>8.4. Readers-Writers Problem &mdash; Computer Systems Fundamentals</title>
<link rel="stylesheet" href="_static/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />
<link rel="stylesheet" href="_static/css/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/css/normalize.css" type="text/css" />
<link rel="stylesheet" href="../../../JSAV/css/JSAV.css" type="text/css" />
<link rel="stylesheet" href="../../../lib/odsaMOD-min.css" type="text/css" />
<link rel="stylesheet" href="_static/css/jquery-1.11.4-smoothness-ui.css" type="text/css" />
<link rel="stylesheet" href="../../../lib/odsaStyle-min.css" type="text/css" />
<link rel="stylesheet" href="_static/css/csf.css" type="text/css" />
<style>
.underline { text-decoration: underline; }
</style>
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '0.4.1',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [['$','$'], ['\\(','\\)']],
displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
processEscapes: true
},
"HTML-CSS": {
scale: "80"
}
});
</script>
<link rel="shortcut icon" href="_static/favicon.ico"/>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="index" title="Computer Systems Fundamentals" href="index.html" />
<link rel="next" title="5. Dining Philosophers Problem and Deadlock" href="DiningPhil.html" />
<link rel="prev" title="3. Producer-Consumer Problem" href="ProdCons.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="ReadWrite.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="ReadWrite.html#"><b>Chapter 1</b></a>
<a class="dropdown-item" href="IntroConcSysOverview.html">&nbsp;&nbsp;&nbsp;1.1. Introduction to Concurrent Systems</a>
<a class="dropdown-item" href="SysAndModels.html">&nbsp;&nbsp;&nbsp;1.2. Systems and Models</a>
<a class="dropdown-item" href="Themes.html">&nbsp;&nbsp;&nbsp;1.3. Themes and Guiding Principles</a>
<a class="dropdown-item" href="Architectures.html">&nbsp;&nbsp;&nbsp;1.4. System Architectures</a>
<a class="dropdown-item" href="StateModels.html">&nbsp;&nbsp;&nbsp;1.5. State Models in UML</a>
<a class="dropdown-item" href="SequenceModels.html">&nbsp;&nbsp;&nbsp;1.6. Sequence Models in UML</a>
<a class="dropdown-item" href="StateModelImplementation.html">&nbsp;&nbsp;&nbsp;1.7. Extended Example: State Model Implementation</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 2</b></a>
<a class="dropdown-item" href="ProcessesOverview.html">&nbsp;&nbsp;&nbsp;2.1. Processes and OS Basics</a>
<a class="dropdown-item" href="Multiprogramming.html">&nbsp;&nbsp;&nbsp;2.2. Processes and Multiprogramming</a>
<a class="dropdown-item" href="KernelMechanics.html">&nbsp;&nbsp;&nbsp;2.3. Kernel Mechanics</a>
<a class="dropdown-item" href="Syscall.html">&nbsp;&nbsp;&nbsp;2.4. System Call Interface</a>
<a class="dropdown-item" href="ProcessCycle.html">&nbsp;&nbsp;&nbsp;2.5. Process Life Cycle</a>
<a class="dropdown-item" href="UnixFile.html">&nbsp;&nbsp;&nbsp;2.6. The UNIX File Abstraction</a>
<a class="dropdown-item" href="EventsSignals.html">&nbsp;&nbsp;&nbsp;2.7. Events and Signals</a>
<a class="dropdown-item" href="Extended2Processes.html">&nbsp;&nbsp;&nbsp;2.8. Extended Example: Listing Files with Processes</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 3</b></a>
<a class="dropdown-item" href="IPCOverview.html">&nbsp;&nbsp;&nbsp;3.1. Concurrency with IPC</a>
<a class="dropdown-item" href="IPCModels.html">&nbsp;&nbsp;&nbsp;3.2. IPC Models</a>
<a class="dropdown-item" href="Pipes.html">&nbsp;&nbsp;&nbsp;3.3. Pipes and FIFOs</a>
<a class="dropdown-item" href="MMap.html">&nbsp;&nbsp;&nbsp;3.4. Shared Memory With Memory-mapped Files</a>
<a class="dropdown-item" href="POSIXvSysV.html">&nbsp;&nbsp;&nbsp;3.5. POSIX vs. System V IPC</a>
<a class="dropdown-item" href="MQueues.html">&nbsp;&nbsp;&nbsp;3.6. Message Passing With Message Queues</a>
<a class="dropdown-item" href="ShMem.html">&nbsp;&nbsp;&nbsp;3.7. Shared Memory</a>
<a class="dropdown-item" href="IPCSems.html">&nbsp;&nbsp;&nbsp;3.8. Semaphores</a>
<a class="dropdown-item" href="Extended3Bash.html">&nbsp;&nbsp;&nbsp;3.9. Extended Example: Bash-lite: A Simple Command-line Shell</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 4</b></a>
<a class="dropdown-item" href="SocketsOverview.html">&nbsp;&nbsp;&nbsp;4.1. Networked Concurrency</a>
<a class="dropdown-item" href="FiveLayer.html">&nbsp;&nbsp;&nbsp;4.2. The TCP/IP Internet Model</a>
<a class="dropdown-item" href="NetApps.html">&nbsp;&nbsp;&nbsp;4.3. Network Applications and Protocols</a>
<a class="dropdown-item" href="Sockets.html">&nbsp;&nbsp;&nbsp;4.4. The Socket Interface</a>
<a class="dropdown-item" href="TCPSockets.html">&nbsp;&nbsp;&nbsp;4.5. TCP Socket Programming: HTTP</a>
<a class="dropdown-item" href="UDPSockets.html">&nbsp;&nbsp;&nbsp;4.6. UDP Socket Programming: DNS</a>
<a class="dropdown-item" href="AppBroadcast.html">&nbsp;&nbsp;&nbsp;4.7. Application-Layer Broadcasting: DHCP</a>
<a class="dropdown-item" href="Extended4CGI.html">&nbsp;&nbsp;&nbsp;4.8. Extended Example: CGI Web Server</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 5</b></a>
<a class="dropdown-item" href="InternetOverview.html">&nbsp;&nbsp;&nbsp;5.1. The Internet and Connectivity</a>
<a class="dropdown-item" href="AppLayer.html">&nbsp;&nbsp;&nbsp;5.2. Application Layer: Overlay Networks</a>
<a class="dropdown-item" href="TransLayer.html">&nbsp;&nbsp;&nbsp;5.3. Transport Layer</a>
<a class="dropdown-item" href="NetSec.html">&nbsp;&nbsp;&nbsp;5.4. Network Security Fundamentals</a>
<a class="dropdown-item" href="NetLayer.html">&nbsp;&nbsp;&nbsp;5.5. Network Layer: IP</a>
<a class="dropdown-item" href="LinkLayer.html">&nbsp;&nbsp;&nbsp;5.6. Link Layer</a>
<a class="dropdown-item" href="Wireless.html">&nbsp;&nbsp;&nbsp;5.7. Wireless Connectivity: Wi-Fi, Bluetooth, and Zigbee</a>
<a class="dropdown-item" href="Extended5DNS.html">&nbsp;&nbsp;&nbsp;5.8. Extended Example: DNS client</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 6</b></a>
<a class="dropdown-item" href="ThreadsOverview.html">&nbsp;&nbsp;&nbsp;6.1. Concurrency with Multithreading</a>
<a class="dropdown-item" href="ProcVThreads.html">&nbsp;&nbsp;&nbsp;6.2. Processes vs. Threads</a>
<a class="dropdown-item" href="RaceConditions.html">&nbsp;&nbsp;&nbsp;6.3. Race Conditions and Critical Sections</a>
<a class="dropdown-item" href="POSIXThreads.html">&nbsp;&nbsp;&nbsp;6.4. POSIX Thread Library</a>
<a class="dropdown-item" href="ThreadArgs.html">&nbsp;&nbsp;&nbsp;6.5. Thread Arguments and Return Values</a>
<a class="dropdown-item" href="ImplicitThreads.html">&nbsp;&nbsp;&nbsp;6.6. Implicit Threading and Language-based Threads</a>
<a class="dropdown-item" href="Extended6Input.html">&nbsp;&nbsp;&nbsp;6.7. Extended Example: Keyboard Input Listener</a>
<a class="dropdown-item" href="Extended6Primes.html">&nbsp;&nbsp;&nbsp;6.8. Extended Example: Concurrent Prime Number Search</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 7</b></a>
<a class="dropdown-item" href="SynchOverview.html">&nbsp;&nbsp;&nbsp;7.1. Synchronization Primitives</a>
<a class="dropdown-item" href="CritSect.html">&nbsp;&nbsp;&nbsp;7.2. Critical Sections and Peterson's Solution</a>
<a class="dropdown-item" href="Locks.html">&nbsp;&nbsp;&nbsp;7.3. Locks</a>
<a class="dropdown-item" href="Semaphores.html">&nbsp;&nbsp;&nbsp;7.4. Semaphores</a>
<a class="dropdown-item" href="Barriers.html">&nbsp;&nbsp;&nbsp;7.5. Barriers</a>
<a class="dropdown-item" href="Condvars.html">&nbsp;&nbsp;&nbsp;7.6. Condition Variables</a>
<a class="dropdown-item" href="Deadlock.html">&nbsp;&nbsp;&nbsp;7.7. Deadlock</a>
<a class="dropdown-item" href="Extended7Events.html">&nbsp;&nbsp;&nbsp;7.8. Extended Example: Event Log File</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 8</b></a>
<a class="dropdown-item" href="SynchProblemsOverview.html">&nbsp;&nbsp;&nbsp;8.1. Synchronization Patterns and Problems</a>
<a class="dropdown-item" href="SynchDesign.html">&nbsp;&nbsp;&nbsp;8.2. Basic Synchronization Design Patterns</a>
<a class="dropdown-item" href="ProdCons.html">&nbsp;&nbsp;&nbsp;8.3. Producer-Consumer Problem</a>
<a class="dropdown-item" href="ReadWrite.html">&nbsp;&nbsp;&nbsp;8.4. Readers-Writers Problem</a>
<a class="dropdown-item" href="DiningPhil.html">&nbsp;&nbsp;&nbsp;8.5. Dining Philosophers Problem and Deadlock</a>
<a class="dropdown-item" href="CigSmokers.html">&nbsp;&nbsp;&nbsp;8.6. Cigarette Smokers Problem and the Limits of Semaphores and Locks</a>
<a class="dropdown-item" href="Extended8ModExp.html">&nbsp;&nbsp;&nbsp;8.7. Extended Example: Parallel Modular Exponentiation</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Chapter 9</b></a>
<a class="dropdown-item" href="ParallelDistributedOverview.html">&nbsp;&nbsp;&nbsp;9.1. Parallel and Distributed Systems</a>
<a class="dropdown-item" href="ParVConc.html">&nbsp;&nbsp;&nbsp;9.2. Parallelism vs. Concurrency</a>
<a class="dropdown-item" href="ParallelDesign.html">&nbsp;&nbsp;&nbsp;9.3. Parallel Design Patterns</a>
<a class="dropdown-item" href="Scaling.html">&nbsp;&nbsp;&nbsp;9.4. Limits of Parallelism and Scaling</a>
<a class="dropdown-item" href="DistTiming.html">&nbsp;&nbsp;&nbsp;9.5. Timing in Distributed Environments</a>
<a class="dropdown-item" href="DistDataStorage.html">&nbsp;&nbsp;&nbsp;9.6. Reliable Data Storage and Location</a>
<a class="dropdown-item" href="DistConsensus.html">&nbsp;&nbsp;&nbsp;9.7. Consensus in Distributed Systems</a>
<a class="dropdown-item" href="Extended9Blockchain.html">&nbsp;&nbsp;&nbsp;9.8. Extended Example: Blockchain Proof-of-Work</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item disabled"><b>Appendix A</b></a>
<a class="dropdown-item" href="CLangOverview.html">&nbsp;&nbsp;&nbsp;A.1. C Language Reintroduction</a>
<a class="dropdown-item" href="Debugging.html">&nbsp;&nbsp;&nbsp;A.2. Documentation and Debugging</a>
<a class="dropdown-item" href="BasicTypes.html">&nbsp;&nbsp;&nbsp;A.3. Basic Types and Pointers</a>
<a class="dropdown-item" href="Arrays.html">&nbsp;&nbsp;&nbsp;A.4. Arrays, Structs, Enums, and Type Definitions</a>
<a class="dropdown-item" href="Functions.html">&nbsp;&nbsp;&nbsp;A.5. Functions and Scope</a>
<a class="dropdown-item" href="Pointers.html">&nbsp;&nbsp;&nbsp;A.6. Pointers and Dynamic Allocation</a>
<a class="dropdown-item" href="Strings.html">&nbsp;&nbsp;&nbsp;A.7. Strings</a>
<a class="dropdown-item" href="FunctionPointers.html">&nbsp;&nbsp;&nbsp;A.8. Function Pointers</a>
<a class="dropdown-item" href="Files.html">&nbsp;&nbsp;&nbsp;A.9. Files</a>
</div>
</li>
</ul>
</div>
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
<li class="nav-item"><a class="nav-link jmu-gold" href="https://w3.cs.jmu.edu/kirkpams/OpenCSF/Books/csf/source/ReadWrite.rst"
target="_blank" rel="nofollow">Show Source</a></li>
</ul>
</nav>
<div class="container center">
«&#160;&#160;<a id="prevmod" href="ProdCons.html">8.3. Producer-Consumer Problem</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a id="nextmod" href="DiningPhil.html">8.5. Dining Philosophers Problem and Deadlock</a>&#160;&#160;»
</div>
<br />
<script type="text/javascript" src="_static/js/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/javascript" src="_static/js/jquery-1.11.4-ui.min.js"></script>
<script type="text/javascript" src="_static/js/forge-0.7.0.min.js"></script>
<script type="text/javascript" src="../../../JSAV/lib/jquery.transit.js"></script>
<script type="text/javascript" src="../../../JSAV/lib/raphael.js"></script>
<script type="text/javascript" src="../../../JSAV/build/JSAV-min.js"></script>
<script type="text/javascript" src="_static/js/config.js"></script>
<script type="text/javascript" src="../../../lib/odsaUtils-min.js"></script>
<script type="text/javascript" src="../../../lib/odsaMOD-min.js"></script>
<script type="text/javascript" src="_static/js/d3-4.13.0.min.js"></script>
<script type="text/javascript" src="_static/js/d3-selection-multi.v1.min.js"></script>
<script type="text/javascript" src="../../../lib/dataStructures.js"></script>
<div class="container">
<script>ODSA.SETTINGS.DISP_MOD_COMP = true;ODSA.SETTINGS.MODULE_NAME = "ReadWrite";ODSA.SETTINGS.MODULE_LONG_NAME = "Readers-Writers Problem";ODSA.SETTINGS.MODULE_CHAPTER = "Synchronization Patterns and Problems"; 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="readers-writers-problem">
<h1>8.4. Readers-Writers Problem<a class="headerlink" href="ReadWrite.html#readers-writers-problem" title="Permalink to this headline"></a></h1>
<p>The <a class="reference internal" href="Glossary.html#term-readers-writers-problem"><span class="xref std std-term">readers-writers problem</span></a> illustrates a second common pattern in
concurrent software. In this problem, multiple readers are sharing concurrent
access to a resource. Unlike the consumers in the producer-consumer problem, the
readers <em>do not change</em> the shared resource in any way; the reader retrieves a
copy of the data, but the original shared copy remains intact. In addition to
the readers, one or more writers are responsible for modifying the data.</p>
<p>To illustrate the readers-writers problem, consider a web-based e-commerce
application. This application is built on a multithreaded server that assigns
requests to distinct threads. Some threads are queries that are requesting
information about the companys available products, their prices, and so on. As
these requests do not modify the inventory or create purchase orders, these
threads are acting as readers. On the other hand, some threads are processing
requests to insert a new order; other threads are initiated from the delivery
team to update the inventory and to indicate that an order has been shipped.
These threads are writers.</p>
<div class="section" id="a-solution-using-lightswitches">
<h2>8.4.1. A Solution Using Lightswitches<a class="headerlink" href="ReadWrite.html#a-solution-using-lightswitches" title="Permalink to this headline"></a></h2>
<p>One common solution for the readers-writers problem aligns with the asymmetric
lightswitch described previously. As the readers allow concurrent access, the
reader thread would use the <code class="docutils literal notranslate"><span class="pre">enter()</span></code> and <code class="docutils literal notranslate"><span class="pre">leave()</span></code> routines to access the
shared resource. The writers, however, require mutual exclusion, both with other
writers and with all of the readers. Consequently, the writers do not need to
employ the lightswitch, simply accessing the semaphore directly.
<a class="reference external" href="ReadWrite.html#cl8-19">Code Listing 8.19</a> shows the framework for this solution.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-19"><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.19:</span>
<span class="cm"> Asymmetric lightswitch solution to readers-writers</span>
<span class="cm"> */</span>
<span class="kt">void</span> <span class="o">*</span>
<span class="nf">reader</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 as a lightswitch */</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="n">ls_t</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">/* Read the shared data */</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>
<span class="kt">void</span> <span class="o">*</span>
<span class="nf">writer</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 as a lightswitch */</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="n">ls_t</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">lightswitch</span><span class="o">-&gt;</span><span class="n">semaphore</span><span class="p">);</span>
<span class="cm">/* Write to the shared data structure */</span>
<span class="n">sem_post</span> <span class="p">(</span><span class="n">lightswitch</span><span class="o">-&gt;</span><span class="n">semaphore</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>
<div class="section" id="fairness-to-writers">
<h2>8.4.2. Fairness to Writers<a class="headerlink" href="ReadWrite.html#fairness-to-writers" title="Permalink to this headline"></a></h2>
<div class="figure mb-2 align-right" id="id2" style="width: 45%">
<span id="unfair"></span><a class="reference internal image-reference" href="_images/CSF-Images.8.2.png"><img class="p-3 mb-2 align-center border border-dark rounded-lg" alt="An unfair timing for the writer" src="_images/CSF-Images.8.2.png" style="width: 95%;" /></a>
<p class="caption align-center px-3"><span class="caption-text"> Figure 8.4.1: An unfair timing for the writer</span></p>
</div>
<p>The solution to the readers-writers problem as shown in <a class="reference external" href="ReadWrite.html#cl8-19">Code Listing 8.19</a> has an important flaw to highlight. This approach fails to achieve
<a class="reference internal" href="Glossary.html#term-fairness"><span class="xref std std-term">fairness</span></a>, particularly in relation to the writers. Specifically,
consider the timing of events shown in <a href="ReadWrite.html#unfair">Figure 8.4.1</a>. In this
scenario, Reader A arrives first and decrements the semaphore. When the writer
arrives and tries to do the same, it gets blocked. The writer must then wait
until <em>all readers</em> have left. Once Reader B arrives, the two readers take turns
leaving and re-entering. Since at least one reader is always in the system, the
writer is blocked indefinitely, a situation known as <a class="reference internal" href="Glossary.html#term-starvation"><span class="xref std std-term">starvation</span></a>.</p>
<p>The writers starvation in this scenario can be fixed by placing a turnstile
before the readers can enter as shown in <a class="reference external" href="ReadWrite.html#cl8-20">Code Listing 8.20</a>. As long
as there is no writer attempting to enter the critical section, the readers can
each pass through the turnstile and invoke <code class="docutils literal notranslate"><span class="pre">enter()</span></code> on the lightswitch.
However, once a writer arrives, it will call <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> on the turnstile
semaphore, blocking new readers from passing through the turnstile. The writer
will then call <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> on the lightswitch semaphore and block. When the
last of the readers that are already in the critical section call <code class="docutils literal notranslate"><span class="pre">leave()</span></code>,
that thread will <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code> to the lightswitch semaphore, allowing the
writer to enter. The writer can then <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code> to the turnstile, allowing
readers to pass through again. The first reader through calls <code class="docutils literal notranslate"><span class="pre">enter()</span></code> on the
lightswitch and gets blocked until the writer leaves.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-20"><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.20:</span>
<span class="cm"> A starvation-free readers-writers solution</span>
<span class="cm"> */</span>
<span class="k">struct</span> <span class="n">args</span> <span class="p">{</span>
<span class="n">ls_t</span> <span class="o">*</span><span class="n">lightswitch</span><span class="p">;</span>
<span class="n">sem_t</span> <span class="o">*</span><span class="n">turnstile</span><span class="p">;</span>
<span class="p">};</span>
<span class="kt">void</span> <span class="o">*</span>
<span class="nf">reader</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 as struct with lightswitch and turnstile */</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">-&gt;</span><span class="n">turnstile</span><span class="p">);</span>
<span class="n">sem_post</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">turnstile</span><span class="p">);</span>
<span class="n">enter</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">lightswitch</span><span class="p">);</span>
<span class="cm">/* Read the shared data */</span>
<span class="n">leave</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">lightswitch</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="nf">writer</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 as struct with lightswitch and turnstile */</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">-&gt;</span><span class="n">turnstile</span><span class="p">);</span>
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">lightswitch</span><span class="o">-&gt;</span><span class="n">semaphore</span><span class="p">);</span>
<span class="n">sem_post</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">turnstile</span><span class="p">);</span>
<span class="cm">/* Write to the shared data structure */</span>
<span class="n">sem_post</span> <span class="p">(</span><span class="n">lightswitch</span><span class="o">-&gt;</span><span class="n">semaphore</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>
<p>Depending on the particular context, it may be acceptable or desirable to use
the solution that potentially allows writer starvation. For instance, if read
accesses to the critical section are extremely fast and concurrent reads are
rare, starvation would not occur; the turnstile would then impose unnecessary
system calls and potential context switches that may accumulate. However, this
cost may be acceptable to mitigate potential delays to the writers.</p>
</div>
<div class="section" id="search-insert-delete-problem">
<h2>8.4.3. Search-Insert-Delete Problem<a class="headerlink" href="ReadWrite.html#search-insert-delete-problem" title="Permalink to this headline"></a></h2>
<p>The <a class="reference internal" href="Glossary.html#term-search-insert-delete-problem"><span class="xref std std-term">search-insert-delete problem</span></a> is a variant on the readers-writers
problem. In this variant, multiple threads can search through a data structure
concurrently; the searchers are essentially identical to the readers from
before. However, the writers are broken into two distinct types of threads:
inserters are adding new data while deleters are removing elements. As with the
original writers, deletions must be mutually exclusive with all other accesses
to the shared data structure. However, insertions have a more relaxed
requirement: they must be mutually exclusive with themselves and with deletions,
but concurrent searches are still allowed. That is, the inserters and searchers
cannot lock each other out, but only one inserter is allowed access at a time;
deleters, on the other hand, require mutual exclusion.</p>
<p>This problem can be solved with slight modifications of the original solution
for the readers-writers. The searcher thread is identical to the reader, as
shown in <a class="reference external" href="ReadWrite.html#cl8-21">Code Listing 8.21</a>.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-21"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.21:</span>
<span class="cm"> Searchers are identical to readers</span>
<span class="cm"> */</span>
<span class="kt">void</span> <span class="o">*</span>
<span class="nf">searcher</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 as a lightswitch */</span>
<span class="n">ls_t</span> <span class="o">*</span><span class="n">search_switch</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">search_switch</span><span class="p">);</span>
<span class="cm">/* critical section */</span>
<span class="n">leave</span> <span class="p">(</span><span class="n">search_switch</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>
<p>Inserters are also very similar to readers. The main difference is that
inserters also require mutual exclusion among themselves, requiring a lock as
shown in <a class="reference external" href="ReadWrite.html#cl8-22">Code Listing 8.22</a>.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-22"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.22:</span>
<span class="cm"> Inserters also require a lock for mutual exclusion to the data structure</span>
<span class="cm"> */</span>
<span class="k">struct</span> <span class="n">ins_args</span> <span class="p">{</span>
<span class="n">ls_t</span> <span class="o">*</span><span class="n">insert_switch</span><span class="p">;</span>
<span class="n">pthread_mutex_t</span> <span class="o">*</span><span class="n">insert_lock</span><span class="p">;</span>
<span class="p">};</span>
<span class="kt">void</span> <span class="o">*</span>
<span class="nf">inserter</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 as a lightswitch */</span>
<span class="k">struct</span> <span class="n">ins_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">ins_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">-&gt;</span><span class="n">insert_switch</span><span class="p">);</span>
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">insert_lock</span><span class="p">);</span>
<span class="cm">/* critical section */</span>
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">insert_lock</span><span class="p">);</span>
<span class="n">leave</span> <span class="p">(</span><span class="n">args</span><span class="o">-&gt;</span><span class="n">insert_switch</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>
<p>To complete the solution, the deleter threads behave identically to the writers.
The only difference is that the deleter must rely on both lightswitches for the
other two types of threads as shown in <a class="reference external" href="ReadWrite.html#cl8-23">Code Listing 8.23</a>. If the
deleter successfully passes the semaphore for the <code class="docutils literal notranslate"><span class="pre">search_switch</span></code>, then there
are no searchers in the critical section and new searchers will be blocked by
the lightswitch. Once the last inserter leaves the critical section, the deleter
would be able to pass the <code class="docutils literal notranslate"><span class="pre">insert_switch</span></code> semaphore and enter the critical
section. Additional inserters would also be locked out at this point. Once the
deleter exits the critical section, inserters and searchers would be allowed back in.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-2 mb-3 notranslate"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.23:</span>
<span class="cm"> Deleters must work with lightswitches for both searchers and inserters</span>
<span class="cm"> */</span>
<span class="kt">void</span> <span class="o">*</span>
<span class="nf">deleter</span> <span class="p">()</span>
<span class="p">{</span>
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">search_switch</span><span class="o">-&gt;</span><span class="n">semaphore</span><span class="p">);</span>
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">insert_switch</span><span class="o">-&gt;</span><span class="n">semaphore</span><span class="p">);</span>
<span class="cm">/* critical section */</span>
<span class="n">sem_post</span> <span class="p">(</span><span class="n">insert_switch</span><span class="o">-&gt;</span><span class="n">semaphore</span><span class="p">);</span>
<span class="n">sem_post</span> <span class="p">(</span><span class="n">search_switch</span><span class="o">-&gt;</span><span class="n">semaphore</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>This solution, which is a variant on the original readers-writers solution, has
the same weakness previously discussed. The deleter threads can potentially face
starvation, as long as there is at least one searcher or inserter in their
critical sections. Interestingly, though, the searcher threads can also face
starvation. Specifically, consider the case where all the searchers leave the
critical section and a deleter has arrived. As long as there are inserters in
the critical section, the deleter cannot enter. However, the deleter has already
successfully locked out future searchers. Consequently, the future searchers
would be effectively locked out by the inserters. Adapting the turnstile
approach used for readers-writers would successfully prevent starvation in this case, too.</p>
<div
id="SynchProbRWSumm"
class="embedContainer"
data-exer-name="SynchProbRWSumm"
data-long-name="Readers Writers Summary Questions"
data-short-name="SynchProbRWSumm"
data-frame-src="../../../Exercises/SynchProblems/SynchProbRWSumm.html?selfLoggingEnabled=false&amp;localMode=true&amp;module=ReadWrite&amp;JXOP-debug=true&amp;JOP-lang=en&amp;JXOP-code=java"
data-frame-width="950"
data-frame-height="550"
data-external="false"
data-points="1.0"
data-required="True"
data-showhide="show"
data-threshold="3"
data-type="ka"
data-exer-id="">
<div class="center">
<div id="SynchProbRWSumm_iframe"></div>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<div class="mt-4 container center">
«&#160;&#160;<a id="prevmod1" href="ProdCons.html">8.3. Producer-Consumer Problem</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a id="nextmod1" href="DiningPhil.html">8.5. Dining Philosophers Problem and Deadlock</a>&#160;&#160;»
</div>
</div>
<br />
<div class="row jmu-dark-purple-bg">
<div class="col-md-12">
<center>
<a id="contact_us" class="btn button-link-no-blue jmu-gold" rel="nofollow" href="mailto:webmaster@opencsf.org" role="button">Contact Us</a>
<a id="license" class="btn button-link-no-blue jmu-gold" rel="nofollow" href="https://w3.cs.jmu.edu/kirkpams/OpenCSF/lib/license.html" target="_blank">License</a>
</center>
</div>
</div>
<script src="_static/js/popper.js-1.14.7-min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="_static/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>