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

737 lines
No EOL
53 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.3. Producer-Consumer 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="4. Readers-Writers Problem" href="ReadWrite.html" />
<link rel="prev" title="2. Basic Synchronization Design Patterns" href="SynchDesign.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="ProdCons.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="ProdCons.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/ProdCons.rst"
target="_blank" rel="nofollow">Show Source</a></li>
</ul>
</nav>
<div class="container center">
«&#160;&#160;<a id="prevmod" href="SynchDesign.html">8.2. Basic Synchronization Design Patterns</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a id="nextmod" href="ReadWrite.html">8.4. Readers-Writers Problem</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 = "ProdCons";ODSA.SETTINGS.MODULE_LONG_NAME = "Producer-Consumer Problem";ODSA.SETTINGS.MODULE_CHAPTER = "Synchronization Patterns and Problems"; ODSA.SETTINGS.BUILD_DATE = "2021-06-01 15:31:51"; ODSA.SETTINGS.BUILD_CMAP = false;JSAV_OPTIONS['lang']='en';JSAV_EXERCISE_OPTIONS['code']='java';</script><div class="section" id="producer-consumer-problem">
<h1>8.3. Producer-Consumer Problem<a class="headerlink" href="ProdCons.html#producer-consumer-problem" title="Permalink to this headline"></a></h1>
<p>One of the most common task structures in concurrent systems is illustrated by
the <a class="reference internal" href="Glossary.html#term-producer-consumer-problem"><span class="xref std std-term">producer-consumer problem</span></a>. In this problem, threads or processes are
divided into two relative types: a producer thread is responsible for performing
an initial task that ends with creating some result and a consumer thread that
takes that initial result for some later task. Between the threads, there is a
shared array or queue that stores the results being passed. One key feature of
this problem is that the consumer removes the data from the queue and <em>consumes</em>
it by using it in some later purpose. There is no way for the consumer thread or
threads to repeatedly access data in the queue.</p>
<p>As an example, consider a researcher who discovers a previously unknown play and
they believe it may have been written by a famous author. As part of their work,
this researcher wants to know if the newly discovered text uses common words
with the same frequency that author used in other works. This work could be done
with a pipe-and-filter application that reads in the content of the texts,
builds a search index of all words based on their frequency, performs some
computation that compares the search indexes of all of the works. One thread is
assigned the tasks of reading in the contents and <em>producing</em> the list of words,
placing a word at a time in a queue. A second thread <em>consumes</em> the words by
removing them from the queue and adding them to the data used to build the
search index. This thread then becomes a producer because it provides the index
to yet another thread that will be performing the index comparisons.</p>
<div class="section" id="producer-consumer-with-unbounded-queue">
<h2>8.3.1. Producer-Consumer with Unbounded Queue<a class="headerlink" href="ProdCons.html#producer-consumer-with-unbounded-queue" title="Permalink to this headline"></a></h2>
<p>As a first variant on this problem, consider two threads that share an unbounded
queue. This approach can be implemented using a linked list approach for the
queue. Specifically, we can assume that there is a <code class="docutils literal notranslate"><span class="pre">queue_t</span></code> structure that
contains pointers to the front and back of the queue, where the nodes in the
queue are of type <code class="docutils literal notranslate"><span class="pre">queue_node_t</span></code>. The nodes all contain pointers to some sort
of <code class="docutils literal notranslate"><span class="pre">data_t</span></code> field. <a class="reference external" href="ProdCons.html#cl8-10">Code Listing 8.10</a> shows the framework for
enqueueing and dequeueing data.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-10"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.10:</span>
<span class="cm"> Enqueue and dequeue operations for a linked list implementation of a queue</span>
<span class="cm"> */</span>
<span class="kt">void</span>
<span class="nf">enqueue_unsafe</span> <span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span><span class="n">queue</span><span class="p">,</span> <span class="n">data_t</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span>
<span class="p">{</span>
<span class="cm">/* Create a new node and make it the new back of the queue */</span>
<span class="n">queue</span><span class="o">-&gt;</span><span class="n">back</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">calloc</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">queue_node_t</span><span class="p">));</span>
<span class="n">assert</span> <span class="p">(</span><span class="n">queue</span><span class="o">-&gt;</span><span class="n">back</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">!=</span> <span class="n">null</span><span class="p">);</span>
<span class="n">queue</span><span class="o">-&gt;</span><span class="n">back</span> <span class="o">=</span> <span class="n">queue</span><span class="o">-&gt;</span><span class="n">back</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
<span class="n">queue</span><span class="o">-&gt;</span><span class="n">back</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">data_t</span> <span class="o">*</span>
<span class="nf">dequeue_unsafe</span> <span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span><span class="n">queue</span><span class="p">)</span>
<span class="p">{</span>
<span class="cm">/* If back = front, then the queue is empty */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">queue</span><span class="o">-&gt;</span><span class="n">back</span> <span class="o">==</span> <span class="n">queue</span><span class="o">-&gt;</span><span class="n">front</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="n">data_t</span> <span class="o">*</span> <span class="n">data</span> <span class="o">=</span> <span class="n">queue</span><span class="o">-&gt;</span><span class="n">front</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">;</span>
<span class="n">queue_node_t</span> <span class="o">*</span> <span class="n">next</span> <span class="o">=</span> <span class="n">queue</span><span class="o">-&gt;</span><span class="n">front</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>
<span class="n">free</span> <span class="p">(</span><span class="n">queue</span><span class="o">-&gt;</span><span class="n">front</span><span class="p">);</span>
<span class="n">queue</span><span class="o">-&gt;</span><span class="n">front</span> <span class="o">=</span> <span class="n">next</span><span class="p">;</span>
<span class="k">return</span> <span class="n">data</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
<p>This implementation, which would be acceptable for a single-threaded
application, has a race condition when used in a concurrent setting.
Specifically, if one thread begins to <code class="docutils literal notranslate"><span class="pre">enqueue()</span></code> some data, another thread
that tries to <code class="docutils literal notranslate"><span class="pre">dequeue()</span></code> the data at the same time may get a <code class="docutils literal notranslate"><span class="pre">NULL</span></code> pointer
because the first thread has not yet reached the line the advances the back
pointer.</p>
<p>The solution here would be to refactor these functions to become a monitor as
shown in <a class="reference external" href="ProdCons.html#cl8-11">Code Listing 8.11</a>. Each function would be passed a
reference to a shared mutex that would be locked on entry and released just
before the function returns. This solution eliminates the race condition
regarding the timing of access to the queues <code class="docutils literal notranslate"><span class="pre">back</span></code> field. Additionally, this
solution is generalizable regardless of the number of producers and consumers.
If there are multiple producers trying to <code class="docutils literal notranslate"><span class="pre">enqueue()</span></code> data, the mutex ensures
that they will not try to manipulate the queue at that same time. For brevity,
<a class="reference external" href="ProdCons.html#cl8-11">Code Listing 8.11</a> calls the functions from <a class="reference external" href="ProdCons.html#cl8-10">Code Listing 8.10</a>.</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.11:</span>
<span class="cm"> A synchronized version of linked list enqueueing and dequeueing</span>
<span class="cm"> */</span>
<span class="kt">void</span>
<span class="nf">enqueue</span> <span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span><span class="n">queue</span><span class="p">,</span> <span class="n">data_t</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="n">pthread_mutex_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
<span class="n">enqueue_unsafe</span> <span class="p">(</span><span class="n">queue</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span>
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">data_t</span> <span class="o">*</span>
<span class="nf">dequeue</span> <span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span><span class="n">queue</span><span class="p">,</span> <span class="n">pthread_mutex_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
<span class="n">data_t</span> <span class="o">*</span> <span class="n">data</span> <span class="o">=</span> <span class="n">dequeue_unsafe</span> <span class="p">(</span><span class="n">queue</span><span class="p">);</span>
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
<span class="k">return</span> <span class="n">data</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
</div>
<div class="section" id="single-producer-single-consumer-solution-using-a-bounded-queue">
<h2>8.3.2. Single Producer-Single Consumer Solution Using a Bounded Queue<a class="headerlink" href="ProdCons.html#single-producer-single-consumer-solution-using-a-bounded-queue" title="Permalink to this headline"></a></h2>
<p>In many cases, the unbounded queue of the previous section is neither feasible
nor desirable. For instance, this approach makes it very easy to launch a
<a class="reference internal" href="Glossary.html#term-denial-of-service"><span class="xref std std-term">denial-of-service</span></a> attack against the application, particularly if this
code is used in a server. <a class="reference external" href="ProdCons.html#cl8-12">Code Listing 8.12</a> shows a single line of
code that quickly exhausts the programs dynamic memory resources, leading to a
system crash.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-12"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0">1
2
3
4
5
6</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.12:</span>
<span class="cm"> A trivial denial-of-service attack against the code in 8.11</span>
<span class="cm"> */</span>
<span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">enqueue</span> <span class="p">(</span><span class="n">queue</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">lock</span><span class="p">);</span>
</pre></div>
</td></tr></table></div>
<p>Given this weakness, systems software typically imposes constraints on the
number of items in the queue. One approach would be to use semaphores with the
linked list queue above. Another approach is to use a finite circular array as
the basis. For this approach, we will still assume the use of a <code class="docutils literal notranslate"><span class="pre">queue_t</span></code> data
type to represent the queue, however the internal implementation uses an array
instead of linked nodes. <a href="ProdCons.html#circarray">Figure 8.3.1</a> illustrates the
structure of the queue.</p>
<div class="figure mb-2 align-right" id="id6" style="width: 40%">
<span id="circarray"></span><a class="reference internal image-reference" href="_images/CSF-Images.8.1.png"><img class="p-3 mb-2 align-center border border-dark rounded-lg" alt="A circular queue using an array" src="_images/CSF-Images.8.1.png" style="width: 90%;" /></a>
<p class="caption align-center px-3"><span class="caption-text"> Figure 8.3.1: A circular queue using an array</span></p>
</div>
<p><a class="reference external" href="ProdCons.html#cl8-13">Code Listing 8.13</a> shows the unsafe version of the <code class="docutils literal notranslate"><span class="pre">enqueue()</span></code> and
<code class="docutils literal notranslate"><span class="pre">dequeue()</span></code> operations for an array implementation of a queue. Within the
<code class="docutils literal notranslate"><span class="pre">queue_t</span></code> data type, contents is an array of pointers to the enqueued data,
while <code class="docutils literal notranslate"><span class="pre">front</span></code> and <code class="docutils literal notranslate"><span class="pre">back</span></code> are indexes into this array. When either of the
indexes are incremented, the operations must recalculate the value modulo the
array size to ensure that the values stay within the bounds of the array. This
approach creates a circular structure, where the spaces in the array can be
reused. Once the back index reaches the end of the array, it would return to the
first position and continue from there.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-13"><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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.13:</span>
<span class="cm"> Enqueue and dequeue operations for an array queue implementation</span>
<span class="cm"> */</span>
<span class="kt">void</span>
<span class="nf">enqueue_unsafe</span> <span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span><span class="n">queue</span><span class="p">,</span> <span class="n">data_t</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span>
<span class="p">{</span>
<span class="cm">/* Store the data in the array and advance the index */</span>
<span class="n">queue</span><span class="o">-&gt;</span><span class="n">contents</span><span class="p">[</span><span class="n">queue</span><span class="o">-&gt;</span><span class="n">back</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">;</span>
<span class="n">queue</span><span class="o">-&gt;</span><span class="n">back</span> <span class="o">%=</span> <span class="n">queue</span><span class="o">-&gt;</span><span class="n">capacity</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">data_t</span> <span class="o">*</span>
<span class="nf">dequeue_unsafe</span> <span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span><span class="n">queue</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">data_t</span> <span class="o">*</span> <span class="n">data</span> <span class="o">=</span> <span class="n">queue</span><span class="o">-&gt;</span><span class="n">contents</span><span class="p">[</span><span class="n">queue</span><span class="o">-&gt;</span><span class="n">front</span><span class="o">++</span><span class="p">];</span>
<span class="n">queue</span><span class="o">-&gt;</span><span class="n">front</span> <span class="o">%=</span> <span class="n">queue</span><span class="o">-&gt;</span><span class="n">capacity</span><span class="p">;</span>
<span class="k">return</span> <span class="n">data</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
<p>The implementation in <a class="reference external" href="ProdCons.html#cl8-13">Code Listing 8.13</a> has a fundamental flaw in
both operations, as neither enforces the limited capacity. This design choice
was intentional, as this code was meant to encapsulate the enqueueing and
dequeueing behavior. That is, we can now reason through the synchronization
issues for the producer-consumer problem without regard for the specific queue
implementation.</p>
<p>To build the rationale for the solution to the producer-consumer problem,
consider <a class="reference external" href="ProdCons.html#cl8-14">Code Listing 8.14</a>. This implementation attempts to keep
track of the number of items (<code class="docutils literal notranslate"><span class="pre">queue-&gt;size</span></code>) in the queue, comparing it with
values that indicate whether the queue is full or empty.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-14"><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.14:</span>
<span class="cm"> An unsuccessful attempt at solving producer-consumer</span>
<span class="cm"> */</span>
<span class="kt">void</span>
<span class="nf">enqueue_failure</span> <span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span><span class="n">queue</span><span class="p">,</span> <span class="n">data_t</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">queue</span><span class="o">-&gt;</span><span class="n">counter</span> <span class="o">==</span> <span class="n">queue</span><span class="o">-&gt;</span><span class="n">capacity</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
<span class="n">enqueue_unsafe</span> <span class="p">(</span><span class="n">queue</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span>
<span class="n">queue</span><span class="o">-&gt;</span><span class="n">counter</span><span class="o">++</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">data_t</span> <span class="o">*</span>
<span class="nf">dequeue_failure</span> <span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span> <span class="n">queue</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">queue</span><span class="o">-&gt;</span><span class="n">counter</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="n">data_t</span> <span class="o">*</span> <span class="n">data</span> <span class="o">=</span> <span class="n">dequeue_unsafe</span> <span class="p">(</span><span class="n">queue</span><span class="p">);</span>
<span class="n">queue</span><span class="o">-&gt;</span><span class="n">counter</span><span class="o">--</span><span class="p">;</span>
<span class="k">return</span> <span class="n">data</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
<p>The attempted solution in <a class="reference external" href="ProdCons.html#cl8-14">Code Listing 8.14</a> fails because it has
race conditions on the queues <code class="docutils literal notranslate"><span class="pre">counter</span></code> variable. If the producer is
attempting to enqueue an item at the same moment the consumer is dequeueing one,
the outcome depends on whether the producers check for available space happens
before or after the consumer decrements the <code class="docutils literal notranslate"><span class="pre">counter</span></code>. A similar race
condition arises if the queue is empty and both functions are called. This race
condition could be fixed by wrapping the accesses to the <code class="docutils literal notranslate"><span class="pre">counter</span></code> with a
mutex.</p>
<p><a class="reference external" href="ProdCons.html#cl8-14">Code Listing 8.14</a> has another flaw from the producers perspective:
<strong>there is no indication that there was a failure to enqueue the item</strong>.
Addressing this failure would require changing the functions interface to
return a status to indicate success or failure. This approach, however, imposes
an undesirable burden on the user. That is, the programmer who is building the
producer and consumer threads or processes must build in a fail-safe mechanism
to respond accordingly if the <code class="docutils literal notranslate"><span class="pre">enqueue()</span></code> or <code class="docutils literal notranslate"><span class="pre">dequeue()</span></code> operations fail.</p>
<p>A better, more user-friendly solution to the producer-consumer problem is to use
semaphores. Note that semaphores incorporate the key functionality that we need:
<strong>atomic incrementing and decrementing of a counter variable</strong>. The previous
approach was trying to re-invent this already-solved problem. <a class="reference external" href="ProdCons.html#cl8-15">Code Listing 8.15</a> shows the framework for solving the producer-consumer problem for a
single producer and single consumer.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-15"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.15:</span>
<span class="cm"> Solution for a single producer and single consumer</span>
<span class="cm"> */</span>
<span class="kt">void</span>
<span class="nf">enqueue</span> <span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span><span class="n">queue</span><span class="p">,</span> <span class="n">data_t</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="n">sem_t</span> <span class="o">*</span><span class="n">space</span><span class="p">,</span> <span class="n">sem_t</span> <span class="o">*</span><span class="n">items</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">space</span><span class="p">);</span>
<span class="n">enqueue_unsafe</span> <span class="p">(</span><span class="n">queue</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span>
<span class="n">sem_post</span> <span class="p">(</span><span class="n">items</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">data_t</span> <span class="o">*</span>
<span class="nf">dequeue</span> <span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span> <span class="n">queue</span><span class="p">,</span> <span class="n">sem_t</span> <span class="o">*</span><span class="n">space</span><span class="p">,</span> <span class="n">sem_t</span> <span class="o">*</span><span class="n">items</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">items</span><span class="p">);</span>
<span class="n">data_t</span> <span class="o">*</span> <span class="n">data</span> <span class="o">=</span> <span class="n">dequeue_unsafe</span> <span class="p">(</span><span class="n">queue</span><span class="p">);</span>
<span class="n">sem_post</span> <span class="p">(</span><span class="n">space</span><span class="p">);</span>
<span class="k">return</span> <span class="n">data</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
<p>The structure of this approach is to use signaling with two semaphores. The key
insight here is that there are actually <em>two</em> bounds that need enforced: a
maximum and a minimum. If the queue is full, then the producer needs to wait
until there is a space available. That is, the producer must call
<code class="docutils literal notranslate"><span class="pre">sem_wait(space)</span></code> and wait if necessary. The <code class="docutils literal notranslate"><span class="pre">space</span></code> semaphore is
initialized to the capacity of the queue, so it would only be 0 if that many
items are already in the queue. Once the consumer has removed an item from the
queue, it performs the counterpart call <code class="docutils literal notranslate"><span class="pre">sem_post(space)</span></code> to alert the
producer that a space is available. In short, the <code class="docutils literal notranslate"><span class="pre">space</span></code> semaphore enforces
the maximum capacity of the queue.</p>
<p>At the same time, the consumer must not attempt to remove an item from the queue
if none have been enqueued. Depending on the internal state of the queue, this
attempt to dequeue an item might return old data that has previously be removed
or an unexpected <code class="docutils literal notranslate"><span class="pre">NULL</span></code> pointer. The <code class="docutils literal notranslate"><span class="pre">items</span></code> semaphore, which is initialized
to 0 and represents the number of enqueued items, enforces this constraint. If
the queue is empty, this semaphore would have an internal value of 0, causing
the consumer to block when it calls <code class="docutils literal notranslate"><span class="pre">sem_wait(items)</span></code>. Once the producer puts
an item into the queue, it would perform the corresponding <code class="docutils literal notranslate"><span class="pre">sem_post(items)</span></code>
that would increment the semaphore and unblock the consumer.</p>
</div>
<div class="section" id="multiple-producers-solution-using-a-bounded-queue">
<h2>8.3.3. Multiple Producers Solution Using a Bounded Queue<a class="headerlink" href="ProdCons.html#multiple-producers-solution-using-a-bounded-queue" title="Permalink to this headline"></a></h2>
<p>The solution in the previous section works successfully if there is only a
single producer. However, if there are multiple producers, the previous solution
will not work and should not be used. The problem is the line highlighted in
<a class="reference external" href="ProdCons.html#cl8-16">Code Listing 8.16</a>. Recall that post-increments in C are not atomic
operations. That is, the internal execution at the machine language level
involves a three-step process: load the value into a register, increment the
value in the register, and store the result back into memory. If two threads try
to perform this increment at the same time, the increments could interfere with
each other.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-16"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0">1
2
3
4
5</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.16:</span>
<span class="cm"> Non-atomic increments are always race conditions</span>
<span class="cm"> */</span>
<span class="n">queue</span><span class="o">-&gt;</span><span class="n">contents</span><span class="p">[</span><span class="n">queue</span><span class="o">-&gt;</span><span class="n">back</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">;</span>
</pre></div>
</td></tr></table></div>
<p>The solution in this case would be to add a lock as shown in <a class="reference external" href="ProdCons.html#cl8-17">Code Listing 8.17</a>. Acquiring and releasing the lock as shown here minimizes the size
of the critical section. That is, the operations on the semaphores do not
require protection. Including the calls to <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>
within the critical section for the lock would unnecessarily prevent the other
producers from manipulating the semaphores, partially eliminating the benefit of
using a semaphore.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-17"><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.17:</span>
<span class="cm"> Solution for a single producer and single consumer</span>
<span class="cm"> */</span>
<span class="kt">void</span>
<span class="nf">enqueue</span> <span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span><span class="n">queue</span><span class="p">,</span> <span class="n">data_t</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="n">sem_t</span> <span class="o">*</span><span class="n">space</span><span class="p">,</span> <span class="n">sem_t</span> <span class="o">*</span><span class="n">items</span><span class="p">,</span>
<span class="n">pthread_mutex_t</span> <span class="o">*</span><span class="n">lock</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">space</span><span class="p">);</span>
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
<span class="n">enqueue_unsafe</span> <span class="p">(</span><span class="n">queue</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span>
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">lock</span><span class="p">);</span>
<span class="n">sem_post</span> <span class="p">(</span><span class="n">items</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
<p>Note that this approach does not require any modification to the <code class="docutils literal notranslate"><span class="pre">dequeue()</span></code>
operation used by the consumer. Since there is only a single consumer, there is
no race condition on incrementing the <code class="docutils literal notranslate"><span class="pre">queue-&gt;front</span></code> variable. This solution
could be extended to multiple consumers by introducing a second lock for
consumers used in <code class="docutils literal notranslate"><span class="pre">dequeue()</span></code> as shown in <a class="reference external" href="ProdCons.html#cl8-18">Code Listing 8.18</a>. It
is important, in this case, to use separate locks rather than simply reusing the
same lock for both producers and consumers. When both the <code class="docutils literal notranslate"><span class="pre">space</span></code> and
<code class="docutils literal notranslate"><span class="pre">items</span></code> semaphores have positive values, then the front and back of the queue
are guaranteed to be in different places. That is, there are multiple items in
the queue, so the producer and consumer within the critical sections would not
be interfering with each other. Consequently, there is no reason that the
producer needs to lock out the consumer, or vice versa.</p>
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate" id="cl8-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</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cm">/* Code Listing 8.18:</span>
<span class="cm"> Solution for a multiple producers and consumers</span>
<span class="cm"> */</span>
<span class="kt">void</span>
<span class="nf">enqueue</span> <span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span><span class="n">queue</span><span class="p">,</span> <span class="n">data_t</span> <span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="n">sem_t</span> <span class="o">*</span><span class="n">space</span><span class="p">,</span> <span class="n">sem_t</span> <span class="o">*</span><span class="n">items</span><span class="p">,</span>
<span class="n">pthread_mutex_t</span> <span class="o">*</span><span class="n">producer_lock</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">space</span><span class="p">);</span>
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">producer_lock</span><span class="p">);</span>
<span class="n">enqueue_unsafe</span> <span class="p">(</span><span class="n">queue</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span>
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">producer_lock</span><span class="p">);</span>
<span class="n">sem_post</span> <span class="p">(</span><span class="n">items</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">data_t</span> <span class="o">*</span>
<span class="nf">dequeue</span> <span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span> <span class="n">queue</span><span class="p">,</span> <span class="n">sem_t</span> <span class="o">*</span><span class="n">space</span><span class="p">,</span> <span class="n">sem_t</span> <span class="o">*</span><span class="n">items</span><span class="p">,</span>
<span class="n">pthread_mutex_t</span> <span class="o">*</span><span class="n">consumer_lock</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">sem_wait</span> <span class="p">(</span><span class="n">items</span><span class="p">);</span>
<span class="n">pthread_mutex_lock</span> <span class="p">(</span><span class="n">consumer_lock</span><span class="p">);</span>
<span class="n">data_t</span> <span class="o">*</span> <span class="n">data</span> <span class="o">=</span> <span class="n">dequeue_unsafe</span> <span class="p">(</span><span class="n">queue</span><span class="p">);</span>
<span class="n">pthread_mutex_unlock</span> <span class="p">(</span><span class="n">consumer_lock</span><span class="p">);</span>
<span class="n">sem_post</span> <span class="p">(</span><span class="n">space</span><span class="p">);</span>
<span class="k">return</span> <span class="n">data</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
<div
id="SynchProbProdSumm"
class="embedContainer"
data-exer-name="SynchProbProdSumm"
data-long-name="Producer Consumer Summary Questions"
data-short-name="SynchProbProdSumm"
data-frame-src="../../../Exercises/SynchProblems/SynchProbProdSumm.html?selfLoggingEnabled=false&amp;localMode=true&amp;module=ProdCons&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="SynchProbProdSumm_iframe"></div>
</div>
</div>
</div>
</div>
</div>
<div class="container">
<div class="mt-4 container center">
«&#160;&#160;<a id="prevmod1" href="SynchDesign.html">8.2. Basic Synchronization Design Patterns</a>
&#160;&#160;::&#160;&#160;
<a class="uplink" href="index.html">Contents</a>
&#160;&#160;::&#160;&#160;
<a id="nextmod1" href="ReadWrite.html">8.4. Readers-Writers Problem</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>