558 lines
No EOL
43 KiB
HTML
558 lines
No EOL
43 KiB
HTML
|
||
<!DOCTYPE html>
|
||
|
||
|
||
|
||
|
||
<html lang="en">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||
|
||
<title>3.8. Semaphores — Computer Systems Fundamentals</title>
|
||
|
||
<link rel="stylesheet" href="_static/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />
|
||
<link rel="stylesheet" href="_static/css/pygments.css" type="text/css" />
|
||
<link rel="stylesheet" href="_static/css/normalize.css" type="text/css" />
|
||
<link rel="stylesheet" href="../../../JSAV/css/JSAV.css" type="text/css" />
|
||
<link rel="stylesheet" href="../../../lib/odsaMOD-min.css" type="text/css" />
|
||
<link rel="stylesheet" href="_static/css/jquery-1.11.4-smoothness-ui.css" type="text/css" />
|
||
<link rel="stylesheet" href="../../../lib/odsaStyle-min.css" type="text/css" />
|
||
<link rel="stylesheet" href="_static/css/csf.css" type="text/css" />
|
||
|
||
<style>
|
||
.underline { text-decoration: underline; }
|
||
</style>
|
||
|
||
<script type="text/javascript">
|
||
var DOCUMENTATION_OPTIONS = {
|
||
URL_ROOT: './',
|
||
VERSION: '0.4.1',
|
||
COLLAPSE_INDEX: false,
|
||
FILE_SUFFIX: '.html',
|
||
HAS_SOURCE: true
|
||
};
|
||
</script>
|
||
|
||
<script type="text/x-mathjax-config">
|
||
MathJax.Hub.Config({
|
||
tex2jax: {
|
||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||
displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
|
||
processEscapes: true
|
||
},
|
||
"HTML-CSS": {
|
||
scale: "80"
|
||
}
|
||
});
|
||
</script>
|
||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||
<link rel="index" title="Index" href="genindex.html" />
|
||
<link rel="search" title="Search" href="search.html" />
|
||
<link rel="index" title="Computer Systems Fundamentals" href="index.html" />
|
||
<link rel="next" title="9. Extended Example: Bash-lite: A Simple Command-line Shell" href="Extended3Bash.html" />
|
||
<link rel="prev" title="7. Shared Memory" href="ShMem.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="IPCSems.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="IPCSems.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/IPCSems.rst"
|
||
target="_blank" rel="nofollow">Show Source</a></li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
|
||
<div class="container center">
|
||
«  <a id="prevmod" href="ShMem.html">3.7. Shared Memory</a>
|
||
  ::  
|
||
<a class="uplink" href="index.html">Contents</a>
|
||
  ::  
|
||
<a id="nextmod" href="Extended3Bash.html">3.9. Extended Example: Bash-lite: A Simple Command-line Shell</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 = "IPCSems";ODSA.SETTINGS.MODULE_LONG_NAME = "Semaphores";ODSA.SETTINGS.MODULE_CHAPTER = "Concurrency with IPC"; 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="semaphores">
|
||
<h1>3.8. Semaphores<a class="headerlink" href="IPCSems.html#semaphores" title="Permalink to this headline">¶</a></h1>
|
||
<p><a class="reference internal" href="Glossary.html#term-semaphore"><span class="xref std std-term">Semaphores</span></a> are different from the other forms of IPC discussed in this chapter,
|
||
because they do not allow for the general exchange of data. That is, you cannot use a semaphore to
|
||
transmit application-specific information from one process to another. Rather, semaphores are used
|
||
to synchronize access to shared resources; that is, semaphores <strong>control the timing of shared
|
||
accesses that may conflict</strong>.</p>
|
||
<p>As a preliminary example, consider a multi-process database application that handles banking
|
||
information. Assume that one process is accessing the file for your account to record a deposit that
|
||
you’ve made. While this is happening, another process also opens your account file to record a
|
||
purchase. You want to make sure that the transaction for the deposit is completely recorded before
|
||
money is removed from your account. That is, you want the application to control the timing of these
|
||
events.</p>
|
||
<p><a class="reference internal" href="Glossary.html#term-synchronization"><span class="xref std std-term">Synchronization</span></a> is a complex topic that will be covered in its own chapter. In this section,
|
||
we will start with the simplest case of synchronization with semaphores: <a class="reference internal" href="Glossary.html#term-signaling-synchronization"><span class="xref std std-term">signaling</span></a> to
|
||
another process that an action has been performed. This concept is very similar to the signals used
|
||
to control the life cycle of a process (e.g., <code class="docutils literal notranslate"><span class="pre">SIGKILL</span></code>). The form of signaling that we are now
|
||
discussing is more generic and allows applications to define their own custom events. That is,
|
||
semaphores let processes inform other processes that <cite>something</cite> has happened, and that something is
|
||
a custom event that only matters to that application. This type of signaling can be considered to
|
||
follow the message passing IPC model, as each signal sent requires a system call.</p>
|
||
<p>Fundamentally, a semaphore is a non-negative integer <a class="footnote-reference" href="IPCSems.html#f19" id="id1">[1]</a> with two operations: incrementing or
|
||
decrementing the value by 1. For a variety of reasons, these two operations have many different
|
||
names that can be used interchangeably. Incrementing a semaphore is also called <em>upping</em>,
|
||
<em>signaling</em>, <em>posting</em>, and <em>V</em> (from the Dutch word <cite>verhogen</cite>, “to raise”). Decrementing a
|
||
semaphore is also called <em>downing</em>, <em>waiting</em>, or <em>P</em> (from the Dutch <cite>proberen</cite>, “to test”). <a class="footnote-reference" href="IPCSems.html#f20" id="id2">[2]</a></p>
|
||
<p>The key behavior is that any process that attempting to decrement a semaphore whose current value is
|
||
0 will become blocked until another process increments the value. If the current value is greater
|
||
than 0 when a process decrements the value, the process can continue processing without waiting.
|
||
When using semaphores, a simple heuristic to consider for the initial value is to ask how many
|
||
processes should be given immediate access. Specifically, the initial value determines how many
|
||
decrements can occur (without any corresponding increments) before processes start to get blocked.
|
||
If a semaphore is initialized to 1, a single process can decrement the semaphore without waiting; a
|
||
second process would be blocked. Initializing the semaphore to 10 would allow 10 processes through.
|
||
This topic will be discussed in more detail in Chapters 8 and 9.</p>
|
||
<p>To illustrate the basic signaling pattern described above, consider two processes (call them A and
|
||
B) that have access to a shared memory region. Assume that A is writing data to the region and B
|
||
needs to know when the writing is completed. (For simplicity, this scenario is a one-time data
|
||
exchange. Once A is finished writing, it will not write again.) To make the signaling happen, A and
|
||
B share access to a semaphore initialized to 0. A will increment the semaphore after it has
|
||
completed writing the data and B will decrement the semaphore before it attempts to read. Observe
|
||
the timings that are possible with this sequence of events:</p>
|
||
<blockquote>
|
||
<div><ul class="simple">
|
||
<li>In one ordering, B attempts to decrement the semaphore before A has completed writing. Since the
|
||
semaphore’s value is 0, B becomes blocked and must wait until A finishes. A eventually completes
|
||
the write and increments the semaphore, unblocking B.</li>
|
||
<li>In a different ordering, A finishes writing and increments the semaphore before B tries to read.
|
||
When B later goes to read the data, the semaphore’s value will be 1 (because A already incremented
|
||
the value) and it can continue without blocking.</li>
|
||
</ul>
|
||
</div></blockquote>
|
||
<p>In either order, the semaphore guarantees that B cannot read any data until A has completed writing
|
||
to the shared memory.</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>In the scenario above, it is important to initialize the semaphore to 0 to achieve the proper
|
||
timing. A common mistake here would be to initialize the semaphore to 1, thinking that we only want
|
||
one of the two processes to access the shared memory. This practice is known as <a class="reference internal" href="Glossary.html#term-mutual-exclusion"><span class="xref std std-term">mutual
|
||
exclusion</span></a>, and will be discussed as an important synchronization pattern. The problem in this
|
||
scenario is that mutual exclusion does not ensure the proper timing. Specifically, if the semaphore
|
||
is initialized to 1 and B decrements the semaphore first, A will be blocked. Consequently, A cannot
|
||
even begin writing to the shared memory and both processes will end up waiting indefinitely.</p>
|
||
</div>
|
||
<div class="section" id="posix-vs-system-v-semaphores">
|
||
<h2>3.8.1. POSIX vs. System V Semaphores<a class="headerlink" href="IPCSems.html#posix-vs-system-v-semaphores" title="Permalink to this headline">¶</a></h2>
|
||
<p><a class="reference internal" href="Glossary.html#term-semaphore"><span class="xref std std-term">Semaphores</span></a>, like message queues and shared memory, have both a POSIX and System
|
||
V interface specification. Key differences between the two versions of semaphores include the following:</p>
|
||
<blockquote>
|
||
<div><ul class="simple">
|
||
<li>POSIX semaphores are created and initialized in a single operation, one at a time. System V
|
||
semaphores are created as a set, and each semaphore can be initialized independently later.</li>
|
||
<li>POSIX semaphores can only be incremented or decremented by 1. System V semaphore operations allow
|
||
processes to specify any unsigned integer that will be added to the semaphore’s value immediately.</li>
|
||
<li>POSIX semaphores provide non-blocking operations that try to decrement the value. If the value is
|
||
currently 0 (which would block the process), the attempt will fail and the process can react in
|
||
other ways. System V semaphores do not provide this feature.</li>
|
||
<li>System V semaphores are identified by <code class="docutils literal notranslate"><span class="pre">key_t</span></code> values. POSIX semaphores can be identified by valid
|
||
POSIX names (begin with a “<code class="docutils literal notranslate"><span class="pre">/</span></code>”) or they can be unnamed.</li>
|
||
</ul>
|
||
</div></blockquote>
|
||
</div>
|
||
<div class="section" id="posix-named-semaphores">
|
||
<h2>3.8.2. POSIX Named Semaphores<a class="headerlink" href="IPCSems.html#posix-named-semaphores" title="Permalink to this headline">¶</a></h2>
|
||
<p>POSIX defines two types of semaphores: named and unnamed. <a class="reference internal" href="Glossary.html#term-named-semaphore"><span class="xref std std-term">Named semaphores</span></a>
|
||
are created using the standard POSIX arguments of <code class="docutils literal notranslate"><span class="pre">name</span></code>, <code class="docutils literal notranslate"><span class="pre">oflag</span></code>, and <code class="docutils literal notranslate"><span class="pre">mode</span></code>, along with an
|
||
initial unsigned integer <code class="docutils literal notranslate"><span class="pre">value</span></code>. The <code class="docutils literal notranslate"><span class="pre">mode</span></code> and <code class="docutils literal notranslate"><span class="pre">value</span></code> parameters must both be included when
|
||
creating a new semaphore, and both must be excluded when connecting to an existing semaphore. The
|
||
<code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> and <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code> functions decrement (wait) or increment (post) the semaphore’s
|
||
value. If the value is currently 0, <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> will block the current process until the value is
|
||
changed by another process calling <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code>. Note that <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code> will only unblock one
|
||
process at a time; if five processes are waiting on the semaphore, then five calls to <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code>
|
||
must be made to unblock them all.</p>
|
||
<div class="topic border border-dark rounded-lg bg-light px-2 mb-3">
|
||
<div class="figure align-left">
|
||
<a class="reference internal image-reference" href="_images/CSF-Images-Library.png"><img alt="Decorative C library image" src="_images/CSF-Images-Library.png" style="width: 100%;" /></a>
|
||
</div>
|
||
<p class="topic-title first pt-2 mb-1">C library functions – <semaphore.h></p><hr class="mt-1" />
|
||
<dl class="docutils">
|
||
<dt><code class="docutils literal notranslate"><span class="pre">sem_t</span> <span class="pre">*sem_open</span> <span class="pre">(const</span> <span class="pre">char</span> <span class="pre">*name,</span> <span class="pre">int</span> <span class="pre">oflag,</span> <span class="pre">...</span>  <span class="pre">/*</span> <span class="pre">mode_t</span> <span class="pre">mode,</span> <span class="pre">unsigned</span> <span class="pre">int</span> <span class="pre">value</span> <span class="pre">*/</span> <span class="pre">);</span></code></dt>
|
||
<dd>Returns (and optionally creates) a named semaphore.</dd>
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">sem_wait</span> <span class="pre">(sem_t</span> <span class="pre">*sem);</span></code></dt>
|
||
<dd>Decrement the semaphore’s value; block if the value is currently 0.</dd>
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">sem_post</span> <span class="pre">(sem_t</span> <span class="pre">*sem);</span></code></dt>
|
||
<dd>Increment the semaphore’s value; resume another process if the value is 0.</dd>
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">sem_close</span> <span class="pre">(sem_t</span> <span class="pre">*sem);</span></code></dt>
|
||
<dd>Close a semaphore.</dd>
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">sem_unlink</span> <span class="pre">(const</span> <span class="pre">char</span> <span class="pre">*name);</span></code></dt>
|
||
<dd>Delete a named semaphore.</dd>
|
||
</dl>
|
||
</div>
|
||
<p><a class="reference external" href="IPCSems.html#cl3-11">Code Listing 3.11</a> illustrates how semaphores can be used to control the timing of two processes. In
|
||
this example, the semaphore is used to guarantee the messages are printed in the correct order
|
||
(“first” then “second” then “third”). Specifically, the semaphore blocks the child process until the
|
||
parent prints “first” and ups the semaphore; then the parent calls <code class="docutils literal notranslate"><span class="pre">wait()</span></code>, which forces it to
|
||
wait until the child exits. It is important to emphasize that named semaphores can be used by
|
||
unrelated processes; they do not have to be parent and child as used in this example.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl3-11"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
16
|
||
17
|
||
18
|
||
19
|
||
20
|
||
21
|
||
22
|
||
23
|
||
24
|
||
25
|
||
26
|
||
27
|
||
28
|
||
29
|
||
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 3.11:</span>
|
||
<span class="cm"> Creating and using a POSIX semaphore to control the timing of parent/child execution</span>
|
||
<span class="cm"> */</span>
|
||
|
||
<span class="cm">/* Create and open the semaphore */</span>
|
||
<span class="n">sem_t</span> <span class="o">*</span><span class="n">sem</span> <span class="o">=</span> <span class="n">sem_open</span> <span class="p">(</span><span class="s">"/OpenCSF_Sema"</span><span class="p">,</span> <span class="n">O_CREAT</span> <span class="o">|</span> <span class="n">O_EXCL</span><span class="p">,</span> <span class="n">S_IRUSR</span> <span class="o">|</span> <span class="n">S_IWUSR</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
|
||
<span class="n">assert</span> <span class="p">(</span><span class="n">sem</span> <span class="o">!=</span> <span class="n">SEM_FAILED</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Fork to create the child process */</span>
|
||
<span class="kt">pid_t</span> <span class="n">child_pid</span> <span class="o">=</span> <span class="n">fork</span><span class="p">();</span>
|
||
<span class="n">assert</span> <span class="p">(</span><span class="n">child_pid</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Note the child inherits a copy of the semaphore connection */</span>
|
||
|
||
<span class="cm">/* Child process: wait for semaphore, print "second", then exit */</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">child_pid</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">sem</span><span class="p">);</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"second</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
|
||
<span class="n">sem_close</span> <span class="p">(</span><span class="n">sem</span><span class="p">);</span>
|
||
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="cm">/* Parent prints then posts to the semaphore and waits on child */</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"first</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
|
||
<span class="n">sem_post</span> <span class="p">(</span><span class="n">sem</span><span class="p">);</span>
|
||
<span class="n">wait</span> <span class="p">(</span><span class="nb">NULL</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Now the child has printed and exited */</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"third</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
|
||
<span class="n">sem_close</span> <span class="p">(</span><span class="n">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>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>In many circumstances, a process may wish to check on the status of a semaphore without getting
|
||
blocked indefinitely. For instance, assume one process is using a semaphore to signal that it has
|
||
completed some important task; another process may want to check on whether the task has been
|
||
completed, but still continue processing even if the event has not happened yet. Downing the
|
||
semaphore with <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> would not work, because it would block the process until the event
|
||
occurs. Instead, POSIX provides two alternative functions for waiting on a semaphore. With
|
||
<code class="docutils literal notranslate"><span class="pre">sem_trywait()</span></code>, a process can try to down the semaphore; however, if the semaphore’s current
|
||
value is 0, then <code class="docutils literal notranslate"><span class="pre">sem_trywait()</span></code> returns an error instead of blocking. Alternatively,
|
||
<code class="docutils literal notranslate"><span class="pre">sem_timedwait()</span></code> allows the process to specify a maximum amount of time to block; if no post
|
||
occurs before the timeout arrives, then the process is unblocked and an error is returned.</p>
|
||
<div class="topic border border-dark rounded-lg bg-light px-2 mb-3">
|
||
<div class="figure align-left">
|
||
<a class="reference internal image-reference" href="_images/CSF-Images-Library.png"><img alt="Decorative C library image" src="_images/CSF-Images-Library.png" style="width: 100%;" /></a>
|
||
</div>
|
||
<p class="topic-title first pt-2 mb-1">C library functions – <semaphore.h></p><hr class="mt-1" />
|
||
<dl class="docutils">
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">sem_trywait</span> <span class="pre">(sem_t</span> <span class="pre">*sem);</span></code></dt>
|
||
<dd>Try to decrement the semaphore; return an error if doing so would block</dd>
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">sem_timedwait</span> <span class="pre">(sem_t</span> <span class="pre">*sem,</span> <span class="pre">const</span> <span class="pre">struct</span> <span class="pre">timespec</span> <span class="pre">*abs_timeout);</span></code></dt>
|
||
<dd>Decrement the semaphore, but place a time limit on the blocking</dd>
|
||
</dl>
|
||
</div>
|
||
</div>
|
||
<div class="section" id="posix-unnamed-semaphores">
|
||
<h2>3.8.3. POSIX Unnamed Semaphores<a class="headerlink" href="IPCSems.html#posix-unnamed-semaphores" title="Permalink to this headline">¶</a></h2>
|
||
<p>POSIX <a class="reference internal" href="Glossary.html#term-unnamed-semaphore"><span class="xref std std-term">unnamed semaphores</span></a> provide a lightweight approach for creating and
|
||
using semaphores. Specifically, where <code class="docutils literal notranslate"><span class="pre">sem_open()</span></code> returns a pointer to a newly allocated
|
||
semaphore, <code class="docutils literal notranslate"><span class="pre">sem_init()</span></code> takes a reference to a semaphore variable (declared as a <code class="docutils literal notranslate"><span class="pre">sem_t</span></code>) that
|
||
has already been allocated within the current process’s memory space and sets the semaphore to the
|
||
value passed. Once the semaphore is initialized, the other functions specified for named semaphores
|
||
(e.g., <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code> and <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code>) can be used.</p>
|
||
<div class="topic border border-dark rounded-lg bg-light px-2 mb-3">
|
||
<div class="figure align-left">
|
||
<a class="reference internal image-reference" href="_images/CSF-Images-Library.png"><img alt="Decorative C library image" src="_images/CSF-Images-Library.png" style="width: 100%;" /></a>
|
||
</div>
|
||
<p class="topic-title first pt-2 mb-1">C library functions – <semaphore.h></p><hr class="mt-1" />
|
||
<dl class="docutils">
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">sem_init</span> <span class="pre">(sem_t</span> <span class="pre">*sem,</span> <span class="pre">int</span> <span class="pre">pshared,</span> <span class="pre">unsigned</span> <span class="pre">int</span> <span class="pre">value);</span></code></dt>
|
||
<dd>Create and initialize a POSIX unnamed semaphore.</dd>
|
||
<dt><code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">sem_destroy</span> <span class="pre">(sem_t</span> <span class="pre">*sem);</span></code></dt>
|
||
<dd>Delete a POSIX unnamed semaphore.</dd>
|
||
</dl>
|
||
</div>
|
||
<p>POSIX unnamed semaphores have one very important difference from named semaphores: <strong>unnamed
|
||
semaphores must exist in shared memory</strong>. That is, the preceding code example would not work with
|
||
unnamed semaphores, because the parent and child processes have distinct memory spaces. As such, the
|
||
<code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> and <code class="docutils literal notranslate"><span class="pre">sem_post()</span></code> calls in that code are meaningless, because they are operating on
|
||
two different semaphores. However, if a shared memory space were set up with <code class="docutils literal notranslate"><span class="pre">shmat()</span></code>, the
|
||
semaphore could be stored within that region and the code would work.</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>macOS provides POSIX named semaphores, but <strong>it does not support unnamed semaphores</strong>. macOS
|
||
programs written with unnamed semaphores <cite>will</cite> (unfortunately) compile, but the program will not
|
||
behave correctly. The <code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> function will return an error and will not block the process.
|
||
As noted previously, applications targeting macOS should generally use the System V IPC interface
|
||
rather than POSIX.</p>
|
||
</div>
|
||
<p>The shared memory requirement for POSIX unnamed semaphores limits their usefulness in terms of IPC.
|
||
They are much more commonly used with <a class="reference internal" href="Glossary.html#term-multithreading"><span class="xref std std-term">multithreaded programs</span></a>, since
|
||
multiple threads in the same process automatically share the same memory space. Using unnamed
|
||
semaphores in that case reduces the kernel system overhead, as the semaphore is stored within the
|
||
process itself.</p>
|
||
<p>One scenario where POSIX unnamed semaphores are very helpful for IPC arises when creating a complex
|
||
shared data structure. For instance, consider a binary search tree consisting of millions of nodes
|
||
that is stored in a shared memory region. If the application needs to associate a distinct semaphore
|
||
with each node, assigning and keeping track of millions of names would be a horrifying burden.
|
||
Instead, each node’s <code class="docutils literal notranslate"><span class="pre">struct</span></code> declaration could include a <code class="docutils literal notranslate"><span class="pre">sem_t</span></code> field. This approach would
|
||
simplify the management of the data structure, allowing each semaphore to be created or destroyed
|
||
automatically with the tree node.</p>
|
||
<table class="docutils footnote" frame="void" id="f19" rules="none">
|
||
<colgroup><col class="label" /><col /></colgroup>
|
||
<tbody valign="top">
|
||
<tr><td class="label"><a class="fn-backref" href="IPCSems.html#id1">[1]</a></td><td>This section is describing the typical implementation of semaphores in most modern OS. The
|
||
original definition of semaphores allowed the values to be negative, too. In the original version,
|
||
decrementing the semaphore would first subtract one from the current value, then check if the
|
||
result was negative; if so, the process would block. In modern implementations, the value is
|
||
checked first; if the current value is zero, the process blocks and the subtraction does not occur
|
||
until later. The difference in behavior has very subtle implications that go beyond the scope of
|
||
this book. For our purposes, either implementation will work sufficiently.</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<table class="docutils footnote" frame="void" id="f20" rules="none">
|
||
<colgroup><col class="label" /><col /></colgroup>
|
||
<tbody valign="top">
|
||
<tr><td class="label"><a class="fn-backref" href="IPCSems.html#id2">[2]</a></td><td><code class="docutils literal notranslate"><span class="pre">P()</span></code> and <code class="docutils literal notranslate"><span class="pre">V()</span></code> were the original names for the semaphore operations. Semaphores were
|
||
proposed by the Dutch computer scientist, Edsger Dijkstra. These names are never used in modern
|
||
systems, but they are included here for historical reference. Our general preference is to use
|
||
decrement/increment, given that this pair clearly indicate how the value changes. We also use
|
||
wait/post, however, in relation to POSIX semaphores to match the functions (<code class="docutils literal notranslate"><span class="pre">sem_wait()</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">sem_post()</span></code>) as named in the interface.</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<div
|
||
id="IPCSemSumm"
|
||
class="embedContainer"
|
||
data-exer-name="IPCSemSumm"
|
||
data-long-name="IPC semaphore questions"
|
||
data-short-name="IPCSemSumm"
|
||
data-frame-src="../../../Exercises/IPC/IPCSemSumm.html?selfLoggingEnabled=false&localMode=true&module=IPCSems&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="2"
|
||
data-type="ka"
|
||
data-exer-id="">
|
||
|
||
<div class="center">
|
||
<div id="IPCSemSumm_iframe"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<div class="container">
|
||
|
||
<div class="mt-4 container center">
|
||
«  <a id="prevmod1" href="ShMem.html">3.7. Shared Memory</a>
|
||
  ::  
|
||
<a class="uplink" href="index.html">Contents</a>
|
||
  ::  
|
||
<a id="nextmod1" href="Extended3Bash.html">3.9. Extended Example: Bash-lite: A Simple Command-line Shell</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> |