Sophie

Sophie

distrib > Mageia > 6 > x86_64 > media > core-updates > by-pkgid > 878cdd00a13d17a73c6619a777ef5d74 > files > 317

rust-doc-1.19.0-1.mga6.x86_64.rpm

<!DOCTYPE HTML>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Graceful Shutdown and Cleanup - The Rust Programming Language</title>
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <base href="">

        <link rel="stylesheet" href="book.css">
        <link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>

        <link rel="shortcut icon" href="favicon.png">

        <!-- Font Awesome -->
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">

        <link rel="stylesheet" href="highlight.css">
        <link rel="stylesheet" href="tomorrow-night.css">
        <style>
            .page-wrapper.has-warning > .nav-chapters {
              /* add height for warning content & margin */
              top: 120px;
            }

            p.warning {
                background-color: rgb(242, 222, 222);
                border-bottom-color: rgb(238, 211, 215);
                border-bottom-left-radius: 4px;
                border-bottom-right-radius: 4px;
                border-bottom-style: solid;
                border-bottom-width: 0.666667px;
                border-image-outset: 0 0 0 0;
                border-image-repeat: stretch stretch;
                border-image-slice: 100% 100% 100% 100%;
                border-image-source: none;
                border-image-width: 1 1 1 1;
                border-left-color: rgb(238, 211, 215);
                border-left-style: solid;
                border-left-width: 0.666667px;
                border-right-color: rgb(238, 211, 215);
                border-right-style: solid;
                border-right-width: 0.666667px;
                border-top-color: rgb(238, 211, 215);
                border-top-left-radius: 4px;
                border-top-right-radius: 4px;
                border-top-style: solid;
                border-top-width: 0.666667px;
                color: rgb(185, 74, 72);
                margin-bottom: 0px;
                margin-left: 0px;
                margin-right: 0px;
                margin-top: 30px;
                padding-bottom: 8px;
                padding-left: 14px;
                padding-right: 35px;
                padding-top: 8px;
            }
            p.warning strong {
                color: rgb(185, 74, 72)
            }
            p.warning a {
                color: rgb(0, 136, 204)
            }
        </style>

        <!-- MathJax -->
        <script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>

        <!-- Fetch JQuery from CDN but have a local fallback -->
        <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
        <script>
            if (typeof jQuery == 'undefined') {
                document.write(unescape("%3Cscript src='jquery.js'%3E%3C/script%3E"));
            }
        </script>
    </head>
    <body class="light">
        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme = localStorage.getItem('theme');
            if (theme == null) { theme = 'light'; }
            $('body').removeClass().addClass(theme);
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var sidebar = localStorage.getItem('sidebar');
            if (sidebar === "hidden") { $("html").addClass("sidebar-hidden") }
            else if (sidebar === "visible") { $("html").addClass("sidebar-visible") }
        </script>

        <div id="sidebar" class="sidebar">
            <ul class="chapter"><li><a href="ch01-00-introduction.html"><strong>1.</strong> Introduction</a></li><li><ul class="section"><li><a href="ch01-01-installation.html"><strong>1.1.</strong> Installation</a></li><li><a href="ch01-02-hello-world.html"><strong>1.2.</strong> Hello, World!</a></li></ul></li><li><a href="ch02-00-guessing-game-tutorial.html"><strong>2.</strong> Guessing Game Tutorial</a></li><li><a href="ch03-00-common-programming-concepts.html"><strong>3.</strong> Common Programming Concepts</a></li><li><ul class="section"><li><a href="ch03-01-variables-and-mutability.html"><strong>3.1.</strong> Variables and Mutability</a></li><li><a href="ch03-02-data-types.html"><strong>3.2.</strong> Data Types</a></li><li><a href="ch03-03-how-functions-work.html"><strong>3.3.</strong> How Functions Work</a></li><li><a href="ch03-04-comments.html"><strong>3.4.</strong> Comments</a></li><li><a href="ch03-05-control-flow.html"><strong>3.5.</strong> Control Flow</a></li></ul></li><li><a href="ch04-00-understanding-ownership.html"><strong>4.</strong> Understanding Ownership</a></li><li><ul class="section"><li><a href="ch04-01-what-is-ownership.html"><strong>4.1.</strong> What is Ownership?</a></li><li><a href="ch04-02-references-and-borrowing.html"><strong>4.2.</strong> References &amp; Borrowing</a></li><li><a href="ch04-03-slices.html"><strong>4.3.</strong> Slices</a></li></ul></li><li><a href="ch05-00-structs.html"><strong>5.</strong> Using Structs to Structure Related Data</a></li><li><ul class="section"><li><a href="ch05-01-defining-structs.html"><strong>5.1.</strong> Defining and Instantiating Structs</a></li><li><a href="ch05-02-example-structs.html"><strong>5.2.</strong> An Example Program Using Structs</a></li><li><a href="ch05-03-method-syntax.html"><strong>5.3.</strong> Method Syntax</a></li></ul></li><li><a href="ch06-00-enums.html"><strong>6.</strong> Enums and Pattern Matching</a></li><li><ul class="section"><li><a href="ch06-01-defining-an-enum.html"><strong>6.1.</strong> Defining an Enum</a></li><li><a href="ch06-02-match.html"><strong>6.2.</strong> The <code>match</code> Control Flow Operator</a></li><li><a href="ch06-03-if-let.html"><strong>6.3.</strong> Concise Control Flow with <code>if let</code></a></li></ul></li><li><a href="ch07-00-modules.html"><strong>7.</strong> Modules</a></li><li><ul class="section"><li><a href="ch07-01-mod-and-the-filesystem.html"><strong>7.1.</strong> <code>mod</code> and the Filesystem</a></li><li><a href="ch07-02-controlling-visibility-with-pub.html"><strong>7.2.</strong> Controlling Visibility with <code>pub</code></a></li><li><a href="ch07-03-importing-names-with-use.html"><strong>7.3.</strong> Importing Names with <code>use</code></a></li></ul></li><li><a href="ch08-00-common-collections.html"><strong>8.</strong> Common Collections</a></li><li><ul class="section"><li><a href="ch08-01-vectors.html"><strong>8.1.</strong> Vectors</a></li><li><a href="ch08-02-strings.html"><strong>8.2.</strong> Strings</a></li><li><a href="ch08-03-hash-maps.html"><strong>8.3.</strong> Hash Maps</a></li></ul></li><li><a href="ch09-00-error-handling.html"><strong>9.</strong> Error Handling</a></li><li><ul class="section"><li><a href="ch09-01-unrecoverable-errors-with-panic.html"><strong>9.1.</strong> Unrecoverable Errors with <code>panic!</code></a></li><li><a href="ch09-02-recoverable-errors-with-result.html"><strong>9.2.</strong> Recoverable Errors with <code>Result</code></a></li><li><a href="ch09-03-to-panic-or-not-to-panic.html"><strong>9.3.</strong> To <code>panic!</code> or Not To <code>panic!</code></a></li></ul></li><li><a href="ch10-00-generics.html"><strong>10.</strong> Generic Types, Traits, and Lifetimes</a></li><li><ul class="section"><li><a href="ch10-01-syntax.html"><strong>10.1.</strong> Generic Data Types</a></li><li><a href="ch10-02-traits.html"><strong>10.2.</strong> Traits: Defining Shared Behavior</a></li><li><a href="ch10-03-lifetime-syntax.html"><strong>10.3.</strong> Validating References with Lifetimes</a></li></ul></li><li><a href="ch11-00-testing.html"><strong>11.</strong> Testing</a></li><li><ul class="section"><li><a href="ch11-01-writing-tests.html"><strong>11.1.</strong> Writing tests</a></li><li><a href="ch11-02-running-tests.html"><strong>11.2.</strong> Running tests</a></li><li><a href="ch11-03-test-organization.html"><strong>11.3.</strong> Test Organization</a></li></ul></li><li><a href="ch12-00-an-io-project.html"><strong>12.</strong> An I/O Project</a></li><li><ul class="section"><li><a href="ch12-01-accepting-command-line-arguments.html"><strong>12.1.</strong> Accepting Command Line Arguments</a></li><li><a href="ch12-02-reading-a-file.html"><strong>12.2.</strong> Reading a File</a></li><li><a href="ch12-03-improving-error-handling-and-modularity.html"><strong>12.3.</strong> Improving Error Handling and Modularity</a></li><li><a href="ch12-04-testing-the-librarys-functionality.html"><strong>12.4.</strong> Testing the Library's Functionality</a></li><li><a href="ch12-05-working-with-environment-variables.html"><strong>12.5.</strong> Working with Environment Variables</a></li><li><a href="ch12-06-writing-to-stderr-instead-of-stdout.html"><strong>12.6.</strong> Writing to <code>stderr</code> instead of <code>stdout</code></a></li></ul></li><li><a href="ch13-00-functional-features.html"><strong>13.</strong> Functional Language Features in Rust</a></li><li><ul class="section"><li><a href="ch13-01-closures.html"><strong>13.1.</strong> Closures</a></li><li><a href="ch13-02-iterators.html"><strong>13.2.</strong> Iterators</a></li><li><a href="ch13-03-improving-our-io-project.html"><strong>13.3.</strong> Improving our I/O Project</a></li><li><a href="ch13-04-performance.html"><strong>13.4.</strong> Performance</a></li></ul></li><li><a href="ch14-00-more-about-cargo.html"><strong>14.</strong> More about Cargo and Crates.io</a></li><li><ul class="section"><li><a href="ch14-01-release-profiles.html"><strong>14.1.</strong> Release Profiles</a></li><li><a href="ch14-02-publishing-to-crates-io.html"><strong>14.2.</strong> Publishing a Crate to Crates.io</a></li><li><a href="ch14-03-cargo-workspaces.html"><strong>14.3.</strong> Cargo Workspaces</a></li><li><a href="ch14-04-installing-binaries.html"><strong>14.4.</strong> Installing Binaries from Crates.io with <code>cargo install</code></a></li><li><a href="ch14-05-extending-cargo.html"><strong>14.5.</strong> Extending Cargo with Custom Commands</a></li></ul></li><li><a href="ch15-00-smart-pointers.html"><strong>15.</strong> Smart Pointers</a></li><li><ul class="section"><li><a href="ch15-01-box.html"><strong>15.1.</strong> <code>Box&lt;T&gt;</code> Points to Data on the Heap and Has a Known Size</a></li><li><a href="ch15-02-deref.html"><strong>15.2.</strong> The <code>Deref</code> Trait Allows Access to the Data Through a Reference</a></li><li><a href="ch15-03-drop.html"><strong>15.3.</strong> The <code>Drop</code> Trait Runs Code on Cleanup</a></li><li><a href="ch15-04-rc.html"><strong>15.4.</strong> <code>Rc&lt;T&gt;</code>, the Reference Counted Smart Pointer</a></li><li><a href="ch15-05-interior-mutability.html"><strong>15.5.</strong> <code>RefCell&lt;T&gt;</code> and the Interior Mutability Pattern</a></li><li><a href="ch15-06-reference-cycles.html"><strong>15.6.</strong> Creating Reference Cycles and Leaking Memory is Safe</a></li></ul></li><li><a href="ch16-00-concurrency.html"><strong>16.</strong> Fearless Concurrency</a></li><li><ul class="section"><li><a href="ch16-01-threads.html"><strong>16.1.</strong> Threads</a></li><li><a href="ch16-02-message-passing.html"><strong>16.2.</strong> Message Passing</a></li><li><a href="ch16-03-shared-state.html"><strong>16.3.</strong> Shared State</a></li><li><a href="ch16-04-extensible-concurrency-sync-and-send.html"><strong>16.4.</strong> Extensible Concurrency: <code>Sync</code> and <code>Send</code></a></li></ul></li><li><a href="ch17-00-oop.html"><strong>17.</strong> Is Rust an Object-Oriented Programming Language?</a></li><li><ul class="section"><li><a href="ch17-01-what-is-oo.html"><strong>17.1.</strong> What Does Object-Oriented Mean?</a></li><li><a href="ch17-02-trait-objects.html"><strong>17.2.</strong> Trait Objects for Using Values of Different Types</a></li><li><a href="ch17-03-oo-design-patterns.html"><strong>17.3.</strong> Object-Oriented Design Pattern Implementations</a></li></ul></li><li><a href="ch18-00-patterns.html"><strong>18.</strong> Patterns Match the Structure of Values</a></li><li><ul class="section"><li><a href="ch18-01-all-the-places-for-patterns.html"><strong>18.1.</strong> All the Places Patterns May be Used</a></li><li><a href="ch18-02-refutability.html"><strong>18.2.</strong> Refutability: Whether a Pattern Might Fail to Match</a></li><li><a href="ch18-03-pattern-syntax.html"><strong>18.3.</strong> All the Pattern Syntax</a></li></ul></li><li><a href="ch19-00-advanced-features.html"><strong>19.</strong> Advanced Features</a></li><li><ul class="section"><li><a href="ch19-01-unsafe-rust.html"><strong>19.1.</strong> Unsafe Rust</a></li><li><a href="ch19-02-advanced-lifetimes.html"><strong>19.2.</strong> Advanced Lifetimes</a></li><li><a href="ch19-03-advanced-traits.html"><strong>19.3.</strong> Advanced Traits</a></li><li><a href="ch19-04-advanced-types.html"><strong>19.4.</strong> Advanced Types</a></li><li><a href="ch19-05-advanced-functions-and-closures.html"><strong>19.5.</strong> Advanced Functions &amp; Closures</a></li></ul></li><li><a href="ch20-00-final-project-a-web-server.html"><strong>20.</strong> Final Project: Building a Multithreaded Web Server</a></li><li><ul class="section"><li><a href="ch20-01-single-threaded.html"><strong>20.1.</strong> A Single Threaded Web Server</a></li><li><a href="ch20-02-slow-requests.html"><strong>20.2.</strong> How Slow Requests Affect Throughput</a></li><li><a href="ch20-03-designing-the-interface.html"><strong>20.3.</strong> Designing the Thread Pool Interface</a></li><li><a href="ch20-04-storing-threads.html"><strong>20.4.</strong> Creating the Thread Pool and Storing Threads</a></li><li><a href="ch20-05-sending-requests-via-channels.html"><strong>20.5.</strong> Sending Requests to Threads Via Channels</a></li><li><a href="ch20-06-graceful-shutdown-and-cleanup.html" class="active"><strong>20.6.</strong> Graceful Shutdown and Cleanup</a></li></ul></li><li><a href="appendix-00.html"><strong>21.</strong> Appendix</a></li><li><ul class="section"><li><a href="appendix-01-keywords.html"><strong>21.1.</strong> A - Keywords</a></li><li><a href="appendix-02-operators.html"><strong>21.2.</strong> B - Operators</a></li><li><strong>21.3.</strong> C - Derivable Traits</li><li><strong>21.4.</strong> D - Nightly Rust</li><li><strong>21.5.</strong> E - Macros</li><li><strong>21.6.</strong> F - Translations</li><li><a href="appendix-07-newest-features.html"><strong>21.7.</strong> G - Newest Features</a></li></ul></li></ul>
        </div>

        <div id="page-wrapper" class="page-wrapper has-warning">

            <div class="page">
                <header><p class="warning">You are reading a <strong>draft</strong> of the next edition of TRPL. For more, go <a href="../index.html">here</a>.</p></header>
                <div id="menu-bar" class="menu-bar">
                    <div class="left-buttons">
                        <i id="sidebar-toggle" class="fa fa-bars"></i>
                        <i id="theme-toggle" class="fa fa-paint-brush"></i>
                    </div>

                    <h1 class="menu-title">The Rust Programming Language</h1>

                    <div class="right-buttons">
                        <i id="print-button" class="fa fa-print" title="Print this book"></i>
                    </div>
                </div>


                <div id="content" class="content">
                    <a class="header" href="ch20-06-graceful-shutdown-and-cleanup.html#graceful-shutdown-and-cleanup" id="graceful-shutdown-and-cleanup"><h2>Graceful Shutdown and Cleanup</h2></a>
<p>The code in Listing 20-21 is responding to requests asynchronously through the
use of a thread pool, as we intended. We get some warnings about fields that
we're not using in a direct way, which are a reminder that we're not cleaning
anything up. When we use <code>CTRL-C</code> to halt the main thread, all the other
threads are stopped immediately as well, even if they're in the middle of
serving a request.</p>
<p>We're now going to implement the <code>Drop</code> trait for <code>ThreadPool</code> to call <code>join</code>
on each of the threads in the pool so that the threads will finish the requests
they're working on. Then we'll implement a way for the <code>ThreadPool</code> to tell the
threads they should stop accepting new requests and shut down. To see this code
in action, we'll modify our server to only accept two requests before
gracefully shutting down its thread pool.</p>
<p>Let's start with implementing <code>Drop</code> for our thread pool. When the pool is
dropped, we should join on all of our threads to make sure they finish their
work. Listing 20-22 shows a first attempt at a <code>Drop</code> implementation; this code
won't quite work yet:</p>
<p><span class="filename">Filename: src/lib.rs</span></p>
<pre><code class="language-rust ignore">impl Drop for ThreadPool {
    fn drop(&amp;mut self) {
        for worker in &amp;mut self.workers {
            println!(&quot;Shutting down worker {}&quot;, worker.id);

            worker.thread.join().unwrap();
        }
    }
}
</code></pre>
<p><span class="caption">Listing 20-22: Joining each thread when the thread pool
goes out of scope</span></p>
<p>We loop through each of the thread pool <code>workers</code>, using <code>&amp;mut</code> because <code>self</code>
is itself a mutable reference and we also need to be able to mutate <code>worker</code>.
We print out a message saying that this particular worker is shutting down, and
then we call <code>join</code> on that worker's thread. If the call to <code>join</code> fails, we
<code>unwrap</code> the error to panic and go into an ungraceful shutdown.</p>
<p>Here's the error we get if we compile this code:</p>
<pre><code class="language-text">error[E0507]: cannot move out of borrowed content
  --&gt; src/lib.rs:65:13
   |
65 |             worker.thread.join().unwrap();
   |             ^^^^^^ cannot move out of borrowed content
</code></pre>
<p>Because we only have a mutable borrow of each <code>worker</code>, we can't call <code>join</code>:
<code>join</code> takes ownership of its argument. In order to solve this, we need a way
to move the <code>thread</code> out of the <code>Worker</code> instance that owns <code>thread</code> so that
<code>join</code> can consume the thread. We saw a way to do this in Listing 17-15: if the
<code>Worker</code> holds an <code>Option&lt;thread::JoinHandle&lt;()&gt;</code> instead, we can call the
<code>take</code> method on the <code>Option</code> to move the value out of the <code>Some</code> variant and
leave a <code>None</code> variant in its place. In other words, a <code>Worker</code> that is running
will have a <code>Some</code> variant in <code>thread</code>, and when we want to clean up a worker,
we'll replace <code>Some</code> with <code>None</code> so the worker doesn't have a thread to run.</p>
<p>So we know we want to update the definition of <code>Worker</code> like this:</p>
<p><span class="filename">Filename: src/lib.rs</span></p>
<pre><pre class="playpen"><code class="language-rust"># #![allow(unused_variables)]
#fn main() {
# use std::thread;
struct Worker {
    id: usize,
    thread: Option&lt;thread::JoinHandle&lt;()&gt;&gt;,
}

#}</code></pre></pre>
<p>Now let's lean on the compiler to find the other places that need to change. We
get two errors:</p>
<pre><code class="language-text">error: no method named `join` found for type
`std::option::Option&lt;std::thread::JoinHandle&lt;()&gt;&gt;` in the current scope
  --&gt; src/lib.rs:65:27
   |
65 |             worker.thread.join().unwrap();
   |                           ^^^^

error[E0308]: mismatched types
  --&gt; src/lib.rs:89:21
   |
89 |             thread,
   |             ^^^^^^ expected enum `std::option::Option`, found
   struct `std::thread::JoinHandle`
   |
   = note: expected type `std::option::Option&lt;std::thread::JoinHandle&lt;()&gt;&gt;`
              found type `std::thread::JoinHandle&lt;_&gt;`
</code></pre>
<p>The second error is pointing to the code at the end of <code>Worker::new</code>; we need
to wrap the <code>thread</code> value in <code>Some</code> when we create a new <code>Worker</code>:</p>
<p><span class="filename">Filename: src/lib.rs</span></p>
<pre><code class="language-rust ignore">impl Worker {
    fn new(id: usize, receiver: Arc&lt;Mutex&lt;mpsc::Receiver&lt;Job&gt;&gt;&gt;) -&gt; Worker {
        // ...snip...

        Worker {
            id,
            thread: Some(thread),
        }
    }
}
</code></pre>
<p>The first error is in our <code>Drop</code> implementation, and we mentioned that we'll be
calling <code>take</code> on the <code>Option</code> value to move <code>thread</code> out of <code>worker</code>. Here's
what that looks like:</p>
<p><span class="filename">Filename: src/lib.rs</span></p>
<pre><code class="language-rust ignore">impl Drop for ThreadPool {
    fn drop(&amp;mut self) {
        for worker in &amp;mut self.workers {
            println!(&quot;Shutting down worker {}&quot;, worker.id);

            if let Some(thread) = worker.thread.take() {
                thread.join().unwrap();
            }
        }
    }
}
</code></pre>
<p>As we saw in Chapter 17, the <code>take</code> method on <code>Option</code> takes the <code>Some</code> variant
out and leaves <code>None</code> in its place. We're using <code>if let</code> to destructure the
<code>Some</code> and get the thread, then call <code>join</code> on the thread. If a worker's thread
is already <code>None</code>, then we know this worker has already had its thread cleaned
up so we don't do anything in that case.</p>
<p>With this, our code compiles without any warnings. Bad news though, this code
doesn't function the way we want it to yet. The key is the logic in the
closures that the spawned threads of the <code>Worker</code> instances run: calling <code>join</code>
won't shut down the threads since they <code>loop</code> forever looking for jobs. If we
try to drop our <code>ThreadPool</code> with this implementation, the main thread will
block forever waiting for the first thread to finish.</p>
<p>To fix this, we're going to modify the threads to listen for either a <code>Job</code> to
run or a signal that they should stop listening and exit the infinite loop. So
instead of <code>Job</code> instances, our channel will send one of these two enum
variants:</p>
<p><span class="filename">Filename: src/lib.rs</span></p>
<pre><pre class="playpen"><code class="language-rust"># #![allow(unused_variables)]
#fn main() {
# struct Job;
enum Message {
    NewJob(Job),
    Terminate,
}

#}</code></pre></pre>
<p>This <code>Message</code> enum will either be a <code>NewJob</code> variant that holds the <code>Job</code> the
thread should run, or it will be a <code>Terminate</code> variant that will cause the
thread to exit its loop and stop.</p>
<p>We need to adjust the channel to use values of type <code>Message</code> rather than type
<code>Job</code>, as shown in Listing 20-23:</p>
<p><span class="filename">Filename: src/lib.rs</span></p>
<pre><code class="language-rust ignore">pub struct ThreadPool {
    workers: Vec&lt;Worker&gt;,
    sender: mpsc::Sender&lt;Message&gt;,
}

// ...snip...

impl ThreadPool {
    // ...snip...
    pub fn new(size: usize) -&gt; ThreadPool {
        assert!(size &gt; 0);

        let (sender, receiver) = mpsc::channel();

        // ...snip...
    }

    pub fn execute&lt;F&gt;(&amp;self, f: F)
        where
            F: FnOnce() + Send + 'static
    {
        let job = Box::new(f);

        self.sender.send(Message::NewJob(job)).unwrap();
    }
}

// ...snip...

impl Worker {
    fn new(id: usize, receiver: Arc&lt;Mutex&lt;mpsc::Receiver&lt;Message&gt;&gt;&gt;) -&gt;
        Worker {

        let thread = thread::spawn(move ||{
            loop {
                let message = receiver.lock().unwrap().recv().unwrap();

                match message {
                    Message::NewJob(job) =&gt; {
                        println!(&quot;Worker {} got a job; executing.&quot;, id);

                        job.call_box();
                    },
                    Message::Terminate =&gt; {
                        println!(&quot;Worker {} was told to terminate.&quot;, id);

                        break;
                    },
                }
            }
        });

        Worker {
            id,
            thread: Some(thread),
        }
    }
}
</code></pre>
<p><span class="caption">Listing 20-23: Sending and receiving <code>Message</code> values and
exiting the loop if a <code>Worker</code> receives <code>Message::Terminate</code></span></p>
<p>We need to change <code>Job</code> to <code>Message</code> in the definition of <code>ThreadPool</code>, in
<code>ThreadPool::new</code> where we create the channel, and in the signature of
<code>Worker::new</code>. The <code>execute</code> method of <code>ThreadPool</code> needs to send jobs wrapped
in the <code>Message::NewJob</code> variant. Then, in <code>Worker::new</code> where we receive a
<code>Message</code> from the channel, we'll process the job if we get the <code>NewJob</code>
variant and break out of the loop if we get the <code>Terminate</code> variant.</p>
<p>With these changes, the code will compile again and continue to function in the
same way as it has been. We'll get a warning, though, because we aren't using
the <code>Terminate</code> variant in any messages. Let's change our <code>Drop</code> implementation
to look like Listing 20-24:</p>
<p><span class="filename">Filename: src/lib.rs</span></p>
<pre><code class="language-rust ignore">impl Drop for ThreadPool {
    fn drop(&amp;mut self) {
        println!(&quot;Sending terminate message to all workers.&quot;);

        for _ in &amp;mut self.workers {
            self.sender.send(Message::Terminate).unwrap();
        }

        println!(&quot;Shutting down all workers.&quot;);

        for worker in &amp;mut self.workers {
            println!(&quot;Shutting down worker {}&quot;, worker.id);

            if let Some(thread) = worker.thread.take() {
                thread.join().unwrap();
            }
        }
    }
}
</code></pre>
<p><span class="caption">Listing 20-24: Sending <code>Message::Terminate</code> to the
workers before calling <code>join</code> on each worker thread</span></p>
<p>We're now iterating over the workers twice, once to send one <code>Terminate</code>
message for each worker, and once to call <code>join</code> on each worker's thread. If we
tried to send a message and join immediately in the same loop, it's not
guaranteed that the worker in the current iteration will be the one that gets
the message from the channel.</p>
<p>To understand better why we need two separate loops, imagine a scenario with
two workers. If we iterated through each worker in one loop, on the first
iteration where <code>worker</code> is the first worker, we'd send a terminate message
down the channel and call <code>join</code> on the first worker's thread. If the first
worker was busy processing a request at that moment, the second worker would
pick up the terminate message from the channel and shut down. We're waiting on
the first worker to shut down, but it never will since the second thread picked
up the terminate message. We're now blocking forever waiting for the first
worker to shut down, and we'll never send the second message to terminate.
Deadlock!</p>
<p>To prevent this, we first put all of our <code>Terminate</code> messages on the channel,
and then we join on all the threads. Because each worker will stop receiving
requests on the channel once it gets a terminate message, we can be sure that
if we send the same number of terminate messages as there are workers, each
worker will receive a terminate message before we call <code>join</code> on its thread.</p>
<p>In order to see this code in action, let's modify <code>main</code> to only accept two
requests before gracefully shutting the server down as shown in Listing 20-25:</p>
<p><span class="filename">Filename: src/bin/main.rs</span></p>
<pre><code class="language-rust ignore">fn main() {
    let listener = TcpListener::bind(&quot;127.0.0.1:8080&quot;).unwrap();
    let pool = ThreadPool::new(4);

    let mut counter = 0;

    for stream in listener.incoming() {
        if counter == 2 {
            println!(&quot;Shutting down.&quot;);
            break;
        }

        counter += 1;

        let stream = stream.unwrap();

        pool.execute(|| {
            handle_connection(stream);
        });
    }
}
</code></pre>
<p><span class="caption">Listing 20-25: Shut down the server after serving two
requests by exiting the loop</span></p>
<p>Only serving two requests isn't behavior you'd like a production web server to
have, but this will let us see the graceful shutdown and cleanup working since
we won't be stopping the server with <code>CTRL-C</code>.</p>
<p>We've added a <code>counter</code> variable that we'll increment every time we receive an
incoming TCP stream. If that counter reaches 2, we'll stop serving requests and
instead break out of the <code>for</code> loop. The <code>ThreadPool</code> will go out of scope at
the end of <code>main</code>, and we'll see the <code>drop</code> implementation run.</p>
<p>Start the server with <code>cargo run</code>, and make three requests. The third request
should error, and in your terminal you should see output that looks like:</p>
<pre><code class="language-text">$ cargo run
   Compiling hello v0.1.0 (file:///projects/hello)
    Finished dev [unoptimized + debuginfo] target(s) in 1.0 secs
     Running `target/debug/hello`
Worker 0 got a job; executing.
Worker 3 got a job; executing.
Shutting down.
Sending terminate message to all workers.
Shutting down all workers.
Shutting down worker 0
Worker 1 was told to terminate.
Worker 2 was told to terminate.
Worker 0 was told to terminate.
Worker 3 was told to terminate.
Shutting down worker 1
Shutting down worker 2
Shutting down worker 3
</code></pre>
<p>You may get a different ordering, of course. We can see how this works from the
messages: workers zero and three got the first two requests, and then on the
third request, we stop accepting connections. When the <code>ThreadPool</code> goes out of
scope at the end of <code>main</code>, its <code>Drop</code> implementation kicks in, and the pool
tells all workers to terminate. The workers each print a message when they see
the terminate message, and then the thread pool calls <code>join</code> to shut down each
worker thread.</p>
<p>One interesting aspect of this particular execution: notice that we sent the
terminate messages down the channel, and before any worker received the
messages, we tried to join worker zero. Worker zero had not yet gotten the
terminate message, so the main thread blocked waiting for worker zero to
finish. In the meantime, each of the workers received the termination messages.
Once worker zero finished, the main thread waited for the rest of the workers
to finish, and they had all received the termination message and were able to
shut down at that point.</p>
<p>Congrats! We now have completed our project, and we have a basic web server
that uses a thread pool to respond asynchronously. We're able to perform a
graceful shutdown of the server, which cleans up all the threads in the pool.
Here's the full code for reference:</p>
<p><span class="filename">Filename: src/bin/main.rs</span></p>
<pre><code class="language-rust ignore">extern crate hello;
use hello::ThreadPool;

use std::io::prelude::*;
use std::net::TcpListener;
use std::net::TcpStream;
use std::fs::File;
use std::thread;
use std::time::Duration;

fn main() {
    let listener = TcpListener::bind(&quot;127.0.0.1:8080&quot;).unwrap();
    let pool = ThreadPool::new(4);

    let mut counter = 0;

    for stream in listener.incoming() {
        if counter == 2 {
            println!(&quot;Shutting down.&quot;);
            break;
        }

        counter += 1;

        let stream = stream.unwrap();

        pool.execute(|| {
            handle_connection(stream);
        });
    }
}

fn handle_connection(mut stream: TcpStream) {
    let mut buffer = [0; 512];
    stream.read(&amp;mut buffer).unwrap();

    let get = b&quot;GET / HTTP/1.1\r\n&quot;;
    let sleep = b&quot;GET /sleep HTTP/1.1\r\n&quot;;

    let (status_line, filename) = if buffer.starts_with(get) {
        (&quot;HTTP/1.1 200 OK\r\n\r\n&quot;, &quot;hello.html&quot;)
    } else if buffer.starts_with(sleep) {
        thread::sleep(Duration::from_secs(5));
        (&quot;HTTP/1.1 200 OK\r\n\r\n&quot;, &quot;hello.html&quot;)
    } else {
        (&quot;HTTP/1.1 404 NOT FOUND\r\n\r\n&quot;, &quot;404.html&quot;)
    };

     let mut file = File::open(filename).unwrap();
     let mut contents = String::new();

     file.read_to_string(&amp;mut contents).unwrap();

     let response = format!(&quot;{}{}&quot;, status_line, contents);

     stream.write(response.as_bytes()).unwrap();
     stream.flush().unwrap();
}
</code></pre>
<p><span class="filename">Filename: src/lib.rs</span></p>
<pre><pre class="playpen"><code class="language-rust"># #![allow(unused_variables)]
#fn main() {
use std::thread;
use std::sync::mpsc;
use std::sync::Arc;
use std::sync::Mutex;

enum Message {
    NewJob(Job),
    Terminate,
}

pub struct ThreadPool {
    workers: Vec&lt;Worker&gt;,
    sender: mpsc::Sender&lt;Message&gt;,
}

trait FnBox {
    fn call_box(self: Box&lt;Self&gt;);
}

impl&lt;F: FnOnce()&gt; FnBox for F {
    fn call_box(self: Box&lt;F&gt;) {
        (*self)()
    }
}

type Job = Box&lt;FnBox + Send + 'static&gt;;

impl ThreadPool {
    /// Create a new ThreadPool.
    ///
    /// The size is the number of threads in the pool.
    ///
    /// # Panics
    ///
    /// The `new` function will panic if the size is zero.
    pub fn new(size: usize) -&gt; ThreadPool {
        assert!(size &gt; 0);

        let (sender, receiver) = mpsc::channel();

        let receiver = Arc::new(Mutex::new(receiver));

        let mut workers = Vec::with_capacity(size);

        for id in 0..size {
            workers.push(Worker::new(id, receiver.clone()));
        }

        ThreadPool {
            workers,
            sender,
        }
    }

    pub fn execute&lt;F&gt;(&amp;self, f: F)
        where
            F: FnOnce() + Send + 'static
    {
        let job = Box::new(f);

        self.sender.send(Message::NewJob(job)).unwrap();
    }
}

impl Drop for ThreadPool {
    fn drop(&amp;mut self) {
        println!(&quot;Sending terminate message to all workers.&quot;);

        for _ in &amp;mut self.workers {
            self.sender.send(Message::Terminate).unwrap();
        }

        println!(&quot;Shutting down all workers.&quot;);

        for worker in &amp;mut self.workers {
            println!(&quot;Shutting down worker {}&quot;, worker.id);

            if let Some(thread) = worker.thread.take() {
                thread.join().unwrap();
            }
        }
    }
}

struct Worker {
    id: usize,
    thread: Option&lt;thread::JoinHandle&lt;()&gt;&gt;,
}

impl Worker {
    fn new(id: usize, receiver: Arc&lt;Mutex&lt;mpsc::Receiver&lt;Message&gt;&gt;&gt;) -&gt;
        Worker {

        let thread = thread::spawn(move ||{
            loop {
                let message = receiver.lock().unwrap().recv().unwrap();

                match message {
                    Message::NewJob(job) =&gt; {
                        println!(&quot;Worker {} got a job; executing.&quot;, id);

                        job.call_box();
                    },
                    Message::Terminate =&gt; {
                        println!(&quot;Worker {} was told to terminate.&quot;, id);

                        break;
                    },
                }
            }
        });

        Worker {
            id,
            thread: Some(thread),
        }
    }
}

#}</code></pre></pre>
<p>There's more we could do here! If you'd like to continue enhancing this
project, here are some ideas:</p>
<ul>
<li>Add more documentation to <code>ThreadPool</code> and its public methods</li>
<li>Add tests of the library's functionality</li>
<li>Change calls to <code>unwrap</code> to more robust error handling</li>
<li>Use <code>ThreadPool</code> to perform some other task rather than serving web requests</li>
<li>Find a thread pool crate on crates.io and implement a similar web server
using the crate instead and compare its API and robustness to the thread pool
we implemented</li>
</ul>
<a class="header" href="ch20-06-graceful-shutdown-and-cleanup.html#summary" id="summary"><h2>Summary</h2></a>
<p>Well done! You've made it to the end of the book! We'd like to thank you for
joining us on this tour of Rust. You're now ready to go out and implement your
own Rust projects or help with other people's. Remember there's a community of
other Rustaceans who would love to help you with any challenges you encounter
on your Rust journey.</p>

                </div>

                <!-- Mobile navigation buttons -->
                
                    <a href="ch20-05-sending-requests-via-channels.html" class="mobile-nav-chapters previous">
                        <i class="fa fa-angle-left"></i>
                    </a>
                

                
                    <a href="appendix-00.html" class="mobile-nav-chapters next">
                        <i class="fa fa-angle-right"></i>
                    </a>
                

            </div>

            
                <a href="ch20-05-sending-requests-via-channels.html" class="nav-chapters previous" title="You can navigate through the chapters using the arrow keys">
                    <i class="fa fa-angle-left"></i>
                </a>
            

            
                <a href="appendix-00.html" class="nav-chapters next" title="You can navigate through the chapters using the arrow keys">
                    <i class="fa fa-angle-right"></i>
                </a>
            

        </div>


        <!-- Local fallback for Font Awesome -->
        <script>
            if ($(".fa").css("font-family") !== "FontAwesome") {
                $('<link rel="stylesheet" type="text/css" href="_FontAwesome/css/font-awesome.css">').prependTo('head');
            }
        </script>

        <!-- Livereload script (if served using the cli tool) -->
        

        <script src="highlight.js"></script>
        <script src="book.js"></script>
    </body>
</html>