602 lines
No EOL
40 KiB
HTML
602 lines
No EOL
40 KiB
HTML
|
||
<!DOCTYPE html>
|
||
|
||
|
||
|
||
|
||
<html lang="en">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||
|
||
<title>7.7. Deadlock — 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="8. Extended Example: Event Log File" href="Extended7Events.html" />
|
||
<link rel="prev" title="6. Condition Variables" href="Condvars.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="Deadlock.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="Deadlock.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/Deadlock.rst"
|
||
target="_blank" rel="nofollow">Show Source</a></li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
|
||
<div class="container center">
|
||
«  <a id="prevmod" href="Condvars.html">7.6. Condition Variables</a>
|
||
  ::  
|
||
<a class="uplink" href="index.html">Contents</a>
|
||
  ::  
|
||
<a id="nextmod" href="Extended7Events.html">7.8. Extended Example: Event Log File</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 = "Deadlock";ODSA.SETTINGS.MODULE_LONG_NAME = "Deadlock";ODSA.SETTINGS.MODULE_CHAPTER = "Synchronization Primitives"; ODSA.SETTINGS.BUILD_DATE = "2021-06-01 15:31:50"; ODSA.SETTINGS.BUILD_CMAP = false;JSAV_OPTIONS['lang']='en';JSAV_EXERCISE_OPTIONS['code']='java';</script><div class="section" id="id1">
|
||
<h1>7.7. Deadlock<a class="headerlink" href="Deadlock.html#id1" title="Permalink to this headline">¶</a></h1>
|
||
<p>The <a class="reference internal" href="Glossary.html#term-synchronization-primitive"><span class="xref std std-term">synchronization primitives</span></a> described in
|
||
this chapter provide flexible mechanisms to solve many problems related to the
|
||
timing of concurrent threads. These mechanisms can enforce mutually exclusive
|
||
access to <a class="reference internal" href="Glossary.html#term-critical-section"><span class="xref std std-term">critical sections</span></a>, they can send signals of
|
||
custom events, they can require a minimum number of threads reach a common
|
||
point, and so on. However, there are common pitfalls and errors that can arise
|
||
from their use. One problem (described in the section on locks) is making the
|
||
critical section the wrong size, introducing slow performance. But that is a
|
||
minor problem in comparison to <a class="reference internal" href="Glossary.html#term-deadlock"><span class="xref std std-term">deadlock</span></a>.</p>
|
||
<p>Deadlock is the <strong>permanent and unresolvable blocking</strong> of two or more threads
|
||
that results from each waiting on the other. It is important to note that
|
||
deadlock is different from <a class="reference internal" href="Glossary.html#term-starvation"><span class="xref std std-term">starvation</span></a>, where a thread may have to wait
|
||
for a long time. For instance, consider a thread that repeatedly tries to lock a
|
||
mutex; when it fails, it goes to sleep for a while and tries again. Now, assume
|
||
this thread is very unlucky and it fails every time. This thread is <em>not</em>
|
||
experiencing deadlock; it is experiencing starvation. The difference is that,
|
||
with starvation, it is <em>possible</em> that the thread might get lucky in the future.
|
||
With deadlock, there is no possibility.</p>
|
||
<p><a class="reference external" href="Deadlock.html#cl7-18">Code Listing 7.18</a> provides a simple illustration of how deadlock
|
||
can happen. There are two threads, running the <code class="docutils literal notranslate"><span class="pre">first()</span></code> and <code class="docutils literal notranslate"><span class="pre">second()</span></code>
|
||
functions. The code for <code class="docutils literal notranslate"><span class="pre">first()</span></code> tries to acquire semaphore <code class="docutils literal notranslate"><span class="pre">sem_a</span></code> before
|
||
<code class="docutils literal notranslate"><span class="pre">sem_b</span></code>, while <code class="docutils literal notranslate"><span class="pre">second()</span></code> acquires them in the opposite order.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl7-18"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
16
|
||
17
|
||
18
|
||
19
|
||
20
|
||
21
|
||
22
|
||
23
|
||
24
|
||
25
|
||
26
|
||
27
|
||
28
|
||
29</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 7.18:</span>
|
||
<span class="cm"> Code that is likely to lead to deadlock</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="cm">/* struct contains shared semaphores */</span>
|
||
<span class="k">struct</span> <span class="n">args</span> <span class="p">{</span>
|
||
<span class="n">sem_t</span> <span class="n">sem_a</span><span class="p">;</span>
|
||
<span class="n">sem_t</span> <span class="n">sem_b</span><span class="p">;</span>
|
||
<span class="p">};</span>
|
||
|
||
<span class="kt">void</span> <span class="o">*</span>
|
||
<span class="nf">first</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">/* Acquire "sem_a" before "sem_b" */</span>
|
||
<span class="n">sem_wait</span> <span class="p">(</span><span class="o">&</span><span class="n">args</span><span class="o">-></span><span class="n">sem_a</span><span class="p">);</span>
|
||
<span class="n">sem_wait</span> <span class="p">(</span><span class="o">&</span><span class="n">args</span><span class="o">-></span><span class="n">sem_b</span><span class="p">);</span>
|
||
<span class="cm">/* other code here */</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="kt">void</span> <span class="o">*</span>
|
||
<span class="nf">second</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">/* Acquire "sem_b" before "sem_a" */</span>
|
||
<span class="n">sem_wait</span> <span class="p">(</span><span class="o">&</span><span class="n">args</span><span class="o">-></span><span class="n">sem_b</span><span class="p">);</span>
|
||
<span class="n">sem_wait</span> <span class="p">(</span><span class="o">&</span><span class="n">args</span><span class="o">-></span><span class="n">sem_a</span><span class="p">);</span>
|
||
<span class="cm">/* other code here */</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>The problem arises if there is a thread switch after one of the threads
|
||
successfully acquires the first semaphore it needs. That is, assume that
|
||
<code class="docutils literal notranslate"><span class="pre">first()</span></code> runs and acquires <code class="docutils literal notranslate"><span class="pre">sem_a</span></code>, then a thread switch occurs. At that
|
||
point, <code class="docutils literal notranslate"><span class="pre">second()</span></code> starts running and acquires <code class="docutils literal notranslate"><span class="pre">sem_b</span></code>. But <code class="docutils literal notranslate"><span class="pre">second()</span></code> gets
|
||
blocked when it tries to acquire <code class="docutils literal notranslate"><span class="pre">sem_a</span></code>, which is held by <code class="docutils literal notranslate"><span class="pre">first()</span></code>. At
|
||
that point, the system switches back to <code class="docutils literal notranslate"><span class="pre">first()</span></code>, which gets blocked trying
|
||
to acquire <code class="docutils literal notranslate"><span class="pre">sem_b</span></code>. At this point, both threads are waiting on each other
|
||
permanently.</p>
|
||
<p>It is important to emphasize that code like that shown in <a class="reference external" href="Deadlock.html#cl7-18">Code Listing 7.18</a> does not guarantee that deadlock occurs. This fact becomes clear
|
||
when you consider <a href="Deadlock.html#deadlockstate">Figure 7.7.1</a>, which shows the state
|
||
model for this code. Once <code class="docutils literal notranslate"><span class="pre">first()</span></code> acquires <code class="docutils literal notranslate"><span class="pre">sem_a</span></code>, the emergence of
|
||
deadlock depends on <code class="docutils literal notranslate"><span class="pre">second()</span></code> waiting on <code class="docutils literal notranslate"><span class="pre">sem_b</span></code> before <code class="docutils literal notranslate"><span class="pre">first()</span></code> does.
|
||
If the order is different, the system could return back to the state in which
|
||
neither semaphore is acquired.</p>
|
||
<div class="figure mb-2 align-center" id="id4">
|
||
<span id="deadlockstate"></span><a class="reference internal image-reference" href="_images/CSF-Images.7.3.png"><img class="p-3 mb-2 align-center border border-dark rounded-lg" alt="State model for Code Listing 7.18" src="_images/CSF-Images.7.3.png" style="width: 80%;" /></a>
|
||
<p class="caption align-center px-3"><span class="caption-text"> Figure 7.7.1: State model for Code Listing 7.18</span></p>
|
||
</div>
|
||
<p>To make the description a little more concrete, imagine that you and a friend
|
||
are sitting at a table to eat. There is one pair of chopsticks available; in
|
||
order to eat, you need both chopsticks. When the food arrives, you both forget
|
||
your manners and try to grab the chopsticks first. You manage to grab one while
|
||
your friend got the other. You’re both so hungry that you refuse to let go of
|
||
the chopstick you have. But neither of you can eat, because you only have one
|
||
chopstick. And since neither of you will give up the one you have, you’re
|
||
stuck.</p>
|
||
<div class="section" id="necessary-conditions">
|
||
<h2>7.7.1. Necessary Conditions<a class="headerlink" href="Deadlock.html#necessary-conditions" title="Permalink to this headline">¶</a></h2>
|
||
<p>So what exactly causes deadlock? First, it’s important to note that deadlock is
|
||
a <a class="reference internal" href="Glossary.html#term-race-condition"><span class="xref std std-term">race condition</span></a>. You might write a program that runs millions of times
|
||
over the span of years, only avoiding deadlock through lucky timing. As the code
|
||
base gets larger and the system gets more complex, the possibility of deadlock
|
||
arising gets even worse. For instance, you might have multiple threads that
|
||
(without your awareness) use synchronization primitives through layers of
|
||
encapsulated code. At some point, the timing of these primitives may line up
|
||
precisely to cause deadlock.</p>
|
||
<p>There are four necessary conditions that can lead to deadlock. The first three
|
||
conditions are generally unavoidable system characteristics. Deadlock could be
|
||
made impossible by eliminating a single one of these characteristics.</p>
|
||
<blockquote>
|
||
<div><ul class="simple">
|
||
<li><strong>Mutual exclusion</strong>: Once a resource has been acquired up to its
|
||
allowable capacity, no other thread is granted access.</li>
|
||
<li><strong>No preemption</strong>: Once a thread has acquired a resource, the
|
||
resource cannot be forcibly taken away. For instance, only the owner of a mutex
|
||
can unlock it.</li>
|
||
<li><strong>Hold and wait</strong>: It is possible that a thread can acquire one
|
||
resource and retain ownership of that resource while waiting on another.</li>
|
||
</ul>
|
||
</div></blockquote>
|
||
<p>In modern, general-purpose computing, these three characteristics are <em>de facto</em>
|
||
requirements. Violating any of these characteristics would make concurrent
|
||
systems development significantly more difficult. For instance, by throwing out
|
||
mutual exclusion, <code class="docutils literal notranslate"><span class="pre">pthread_mutex_lock()</span></code> would not block a thread if the mutex
|
||
has already been acquired. By eliminating the <em>no preemption</em> characteristic, a
|
||
thread would repeatedly need to check if it still holds the mutex or if the
|
||
semaphore’s value is still acceptable.</p>
|
||
<p>Eliminating <em>hold and wait</em> would lead to devastating and undesirable
|
||
performance. For instance, consider a database with millions of records, each of
|
||
which can be locked independently. Once a transaction is ready to commit, the
|
||
thread may acquire a single manager lock for the entire database. The reason for
|
||
this split design is that manipulating the local record may require several
|
||
operations and take a while, but they are independent and can happen in
|
||
parallel. The final commit must happen one at a time, but it is very quick.
|
||
Eliminating <em>hold and wait</em> would create the worst possible combination. Since
|
||
both locks would have to be acquired and released at the same time, it would be
|
||
impossible for the records to be manipulated in parallel. At the same time, the
|
||
manager lock would have to be held for far too long while a single record is manipulated.</p>
|
||
<p>Ultimately, the three characteristics above are unavoidable and undesirable in
|
||
modern systems. But it’s important to note that these three characteristics by
|
||
themselves are not sufficient for deadlock. Deadlock is a race condition that
|
||
arises by the fourth necessary condition.</p>
|
||
<blockquote>
|
||
<div><ul class="simple">
|
||
<li><strong>Circular wait</strong>: One thread needs a resource held by another, while
|
||
this second thread needs a different resource held by the first.</li>
|
||
</ul>
|
||
</div></blockquote>
|
||
<p>Circular wait can be extended for more than two threads intuitively. Thread A
|
||
needs something from thread B, which needs something from thread C, which is
|
||
waiting on thread A. This chain of dependencies can be made arbitrarily long.
|
||
Counterintuitively, circular wait can also arise even if there are multiple
|
||
copies of a resource. This is a complex situation that arises in very advanced
|
||
types of systems, though, and we refer interested readers to textbooks on OS
|
||
design for more information.</p>
|
||
<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>It is a common mistake to assume that deadlock only arises with certain types of
|
||
synchronization primitives, such as mutex locks. This confusion arises because
|
||
the term <em>mutual exclusion</em> is often used to mean that only one thread has
|
||
access to a critical section. The term is used more broadly here, allowing for
|
||
the possibility that there may be multiple concurrent accesses; however, those
|
||
accesses are blocking out some others. Ultimately, deadlock can arise with the
|
||
use of locks, semaphores, barriers, or condition variables.</p>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="livelock-and-false-solutions">
|
||
<h2>7.7.2. Livelock and False Solutions<a class="headerlink" href="Deadlock.html#livelock-and-false-solutions" title="Permalink to this headline">¶</a></h2>
|
||
<p><a class="reference internal" href="Glossary.html#term-livelock"><span class="xref std std-term">Livelock</span></a> is a race condition that is similar to deadlock, though there
|
||
is a slight difference. The key distinction with deadlock and livelock is
|
||
whether or not the thread is changing state and executing anything. With
|
||
deadlock, a thread is blocked and not executing any code; with livelock, the
|
||
thread repeatedly changes state between blocked and unblocked, but accomplishes nothing.</p>
|
||
<p>As a simple illustration of livelock, consider <a class="reference external" href="Deadlock.html#cl7-19">Code Listing 7.19</a>,
|
||
which attempts to fix the deadlock in the example above. In this code, after
|
||
successfully acquiring the first semaphore, the threads use <code class="docutils literal notranslate"><span class="pre">sem_try_wait()</span></code>
|
||
on the second. If the wait fails (because the semaphore is locked by the other
|
||
thread), the thread releases the semaphore it has first acquired and starts over.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl7-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
|
||
26
|
||
27
|
||
28
|
||
29
|
||
30
|
||
31
|
||
32
|
||
33
|
||
34
|
||
35
|
||
36
|
||
37</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 7.19:</span>
|
||
<span class="cm"> Livelock occurs when the system is not deadlocked but no work is done</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="kt">void</span> <span class="o">*</span>
|
||
<span class="nf">first</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">/* Acquire "sem_a" before trying to acquire "sem_b" */</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="n">sem_wait</span> <span class="p">(</span><span class="o">&</span><span class="n">args</span><span class="o">-></span><span class="n">sem_a</span><span class="p">);</span>
|
||
<span class="cm">/* Now try for the sem_b, breaking out if successful */</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">sem_try_wait</span> <span class="p">(</span><span class="o">&</span><span class="n">args</span><span class="o">-></span><span class="n">sem_b</span><span class="p">))</span>
|
||
<span class="k">break</span><span class="p">;</span>
|
||
<span class="cm">/* Failed to acquire sem_b, so start over */</span>
|
||
<span class="n">sem_signal</span> <span class="p">(</span><span class="o">&</span><span class="n">args</span><span class="o">-></span><span class="n">sem_a</span><span class="p">);</span>
|
||
<span class="p">}</span>
|
||
<span class="cm">/* other code here */</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="kt">void</span> <span class="o">*</span>
|
||
<span class="nf">second</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">/* Acquire "sem_b" before trying to acquire "sem_a" */</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="n">sem_wait</span> <span class="p">(</span><span class="o">&</span><span class="n">args</span><span class="o">-></span><span class="n">sem_b</span><span class="p">);</span>
|
||
<span class="cm">/* Now try for the sem_a, breaking out if successful */</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">sem_try_wait</span> <span class="p">(</span><span class="o">&</span><span class="n">args</span><span class="o">-></span><span class="n">sem_a</span><span class="p">))</span>
|
||
<span class="k">break</span><span class="p">;</span>
|
||
<span class="cm">/* Failed to acquire sem_a, so start over */</span>
|
||
<span class="n">sem_signal</span> <span class="p">(</span><span class="o">&</span><span class="n">args</span><span class="o">-></span><span class="n">sem_b</span><span class="p">);</span>
|
||
<span class="p">}</span>
|
||
<span class="cm">/* other code here */</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>This code makes deadlock impossible by voluntarily breaking the characteristic
|
||
of hold and wait. Note that it works in this scenario because no work is done
|
||
after the first semaphore is acquired. This approach is not generalizable,
|
||
though, because most systems will perform work in between the two semaphore
|
||
acquisitions; in many instances, that work performed cannot be undone.</p>
|
||
<p>While the code avoids deadlock, it still allows for the possibility of livelock.
|
||
That is, it is possible that both threads <em>repeatedly</em> are successful when
|
||
acquiring the first semaphore, leading to both failing at the second. Then both
|
||
threads release the semaphore they hold and start over again. If this keeps
|
||
happening, the threads are experiencing livelock. They are not in deadlock
|
||
because there is the <em>possibility</em> that a good timing can lead to recovery.
|
||
However, unlucky timing is causing the threads to repeatedly block each other,
|
||
preventing the system from making progress.</p>
|
||
<p>In practice, this code sample is unlikely to experience livelock for a long
|
||
time. Specifically, it is very improbable that a thread switch occurs at the
|
||
exact same moment repeatedly. But this code structure is a very simple and
|
||
special case. As such, this structure is not considered a reliable solution to
|
||
avoiding deadlock.</p>
|
||
</div>
|
||
<div class="section" id="avoiding-deadlock">
|
||
<h2>7.7.3. Avoiding Deadlock<a class="headerlink" href="Deadlock.html#avoiding-deadlock" title="Permalink to this headline">¶</a></h2>
|
||
<p>As three of the deadlock conditions (mutual exclusion, no preemption, hold and
|
||
wait) are standard features in modern systems, the typical solution to the
|
||
avoiding deadlock in software<a class="footnote-reference" href="Deadlock.html#f45" id="id3">[1]</a> is to avoid circular waiting. There are a
|
||
variety of strategies that can be employed to avoid circular waiting that can be
|
||
applied, depending on the needs of the system being built.</p>
|
||
<blockquote>
|
||
<div><ul class="simple">
|
||
<li>Impose an ordering on resources. If one thread acquires <code class="docutils literal notranslate"><span class="pre">sem_a</span></code> prior to
|
||
acquiring <code class="docutils literal notranslate"><span class="pre">sem_b</span></code>, require other threads to follow this order.</li>
|
||
<li>Use timed or non-blocking variants that can provide immediate notification of
|
||
failure. If a function like <code class="docutils literal notranslate"><span class="pre">pthread_mutex_trylock()</span></code> or
|
||
<code class="docutils literal notranslate"><span class="pre">pthread_cond_timedwait()</span></code> returns an error, release other held resources and
|
||
try again later.</li>
|
||
<li>Limit the number of potential thread accesses. For instance, consider a
|
||
scenario where there are five resource instances, and each thread needs two of
|
||
them. Using a semaphore initialized to four would guarantee at least one thread
|
||
will always have access to both the instances it needs; this strategy allows
|
||
that thread to finish its work, eventually releasing both resource instances
|
||
for the other threads to use.</li>
|
||
<li>Employ higher-level synchronization primitives and strategies. In the next
|
||
chapter, we describe some common well-known solutions that are known to be
|
||
deadlock-free.</li>
|
||
</ul>
|
||
</div></blockquote>
|
||
<table class="docutils footnote" frame="void" id="f45" rules="none">
|
||
<colgroup><col class="label" /><col /></colgroup>
|
||
<tbody valign="top">
|
||
<tr><td class="label"><a class="fn-backref" href="Deadlock.html#id3">[1]</a></td><td>Advanced systems software, such as OS kernels, use a variety of
|
||
techniques for solving the deadlock problem. These include applying the
|
||
Banker’s algorithm for deadlock avoidance or executing deadlock detection
|
||
algorithms that can alert a system administrator. Each approach has its
|
||
benefits and drawbacks, and there is no universally accepted solution.</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<div
|
||
id="SynchDeadlockSumm"
|
||
class="embedContainer"
|
||
data-exer-name="SynchDeadlockSumm"
|
||
data-long-name="Deadlock questions"
|
||
data-short-name="SynchDeadlockSumm"
|
||
data-frame-src="../../../Exercises/Synch/SynchDeadlockSumm.html?selfLoggingEnabled=false&localMode=true&module=Deadlock&JXOP-debug=true&JOP-lang=en&JXOP-code=java"
|
||
data-frame-width="950"
|
||
data-frame-height="550"
|
||
data-external="false"
|
||
data-points="1.0"
|
||
data-required="True"
|
||
data-showhide="show"
|
||
data-threshold="3"
|
||
data-type="ka"
|
||
data-exer-id="">
|
||
|
||
<div class="center">
|
||
<div id="SynchDeadlockSumm_iframe"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<div class="container">
|
||
|
||
<div class="mt-4 container center">
|
||
«  <a id="prevmod1" href="Condvars.html">7.6. Condition Variables</a>
|
||
  ::  
|
||
<a class="uplink" href="index.html">Contents</a>
|
||
  ::  
|
||
<a id="nextmod1" href="Extended7Events.html">7.8. Extended Example: Event Log File</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> |