<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: HZNPrince</title>
    <description>The latest articles on DEV Community by HZNPrince (@hznprince).</description>
    <link>https://dev.to/hznprince</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3581924%2Fb8eb4bf7-bf50-4073-886f-3e9bcc626e08.jpeg</url>
      <title>DEV Community: HZNPrince</title>
      <link>https://dev.to/hznprince</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hznprince"/>
    <language>en</language>
    <item>
      <title>I Thought I Understood Threads. Then I Read Atomics and Locks.</title>
      <dc:creator>HZNPrince</dc:creator>
      <pubDate>Fri, 10 Apr 2026 12:18:01 +0000</pubDate>
      <link>https://dev.to/hznprince/i-thought-i-understood-threads-then-i-read-atomics-and-locks-2b7g</link>
      <guid>https://dev.to/hznprince/i-thought-i-understood-threads-then-i-read-atomics-and-locks-2b7g</guid>
      <description>&lt;p&gt;Let me paint a picture.&lt;/p&gt;

&lt;p&gt;You're writing a Rust program. It starts, runs top to bottom, and exits. One thread. One lane of traffic. Fine — until you want two things to happen &lt;em&gt;at the same time&lt;/em&gt;. Maybe you want to download a file while showing a progress bar. Maybe you're writing a server that needs to handle multiple requests. Maybe you just want to go fast.&lt;/p&gt;

&lt;p&gt;That's when threads enter the picture. And that's when most languages say "good luck" and hand you a loaded footgun.&lt;/p&gt;

&lt;p&gt;Rust does something different.&lt;/p&gt;




&lt;h2&gt;
  
  
  Starting a Thread is Stupidly Simple
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello from the main thread."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello from another thread!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.id&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"This is my thread id: {id:?}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;std::thread::spawn&lt;/code&gt; takes a function, hands it to a new thread, and gets out of the way. That's it.&lt;/p&gt;

&lt;p&gt;But here's the first gotcha: &lt;strong&gt;if &lt;code&gt;main()&lt;/code&gt; returns, the whole program dies&lt;/strong&gt; — even if other threads are still running. So if you want to wait for a thread to finish, you need to &lt;code&gt;.join()&lt;/code&gt; it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// wait here until the thread is done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In practice, you'll almost always pass a &lt;strong&gt;closure&lt;/strong&gt; instead of a named function, because closures let you capture values and move them into the thread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{n}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;move&lt;/code&gt; keyword is important. Without it, the closure would borrow &lt;code&gt;numbers&lt;/code&gt; by reference — and the compiler would immediately yell at you, because the spawned thread could potentially outlive the variable. Rust catches this at compile time. No segfaults. No "works on my machine."&lt;/p&gt;

&lt;h3&gt;
  
  
  Scoped Threads — When You Know the Lifetime
&lt;/h3&gt;

&lt;p&gt;Sometimes you &lt;em&gt;know&lt;/em&gt; a thread won't outlive a certain scope. For that, &lt;code&gt;std::thread::scope&lt;/code&gt; lets you borrow local variables safely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="nf"&gt;.spawn&lt;/span&gt;&lt;span class="p"&gt;(||&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"length: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="nf"&gt;.spawn&lt;/span&gt;&lt;span class="p"&gt;(||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{n}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// all scoped threads are automatically joined when we reach here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both threads can borrow &lt;code&gt;numbers&lt;/code&gt; — no &lt;code&gt;move&lt;/code&gt;, no &lt;code&gt;Arc&lt;/code&gt;, no cloning. Clean and safe.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A quick piece of history:&lt;/strong&gt; The original scoped thread API before Rust 1.0 had a subtle bug — it assumed an object's destructor would always run, which let you write "safe" code that was actually unsound. The fix was radical: &lt;code&gt;std::mem::forget&lt;/code&gt; was made safe (to make the assumption explicit), and scoped threads were removed entirely. They came back in Rust 1.63 with a new design that doesn't rely on destructors at all. This incident is affectionately known as &lt;strong&gt;The Leakpocalypse&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Okay But How Do You Actually Share Data?
&lt;/h2&gt;

&lt;p&gt;So you've got two threads. Now you want them to look at the same data. Here's where things get interesting.&lt;/p&gt;

&lt;p&gt;You have three real options.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 1: Statics.&lt;/strong&gt; A &lt;code&gt;static&lt;/code&gt; belongs to the whole program, lives forever, and any thread can borrow it freely. Simple, but inflexible — you have to know the value at compile time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(||&lt;/span&gt; &lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Option 2: Leaking.&lt;/strong&gt; You can deliberately "forget" to free memory using &lt;code&gt;Box::leak&lt;/code&gt;, which gives you a &lt;code&gt;'static&lt;/code&gt; reference. Works in a pinch, but leaking memory on purpose is the kind of thing that comes back to bite you if you do it repeatedly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option 3: &lt;code&gt;Arc&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/strong&gt; This is what you'll actually use.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Arc&lt;/code&gt; stands for &lt;em&gt;Atomically Reference Counted&lt;/em&gt;. The idea is elegant: instead of one owner, you have &lt;em&gt;shared&lt;/em&gt; ownership, tracked by a counter. Every time you clone an &lt;code&gt;Arc&lt;/code&gt;, the counter goes up. When a clone is dropped, the counter goes down. When it hits zero, the value is freed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// same memory, counter = 2&lt;/span&gt;

&lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// counter → 1 when this thread finishes&lt;/span&gt;
&lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// counter → 0, memory freed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might be wondering: what's the difference between &lt;code&gt;Arc&lt;/code&gt; and &lt;code&gt;Rc&lt;/code&gt;? One word — threads.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;Rc&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;Arc&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Thread-safe&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Counter updates&lt;/td&gt;
&lt;td&gt;Non-atomic&lt;/td&gt;
&lt;td&gt;Atomic (hence the A)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overhead&lt;/td&gt;
&lt;td&gt;Lower&lt;/td&gt;
&lt;td&gt;Slightly higher&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use &lt;code&gt;Rc&lt;/code&gt; when you're on a single thread and need shared ownership. Use &lt;code&gt;Arc&lt;/code&gt; when multiple threads are involved. The compiler will stop you if you try to send an &lt;code&gt;Rc&lt;/code&gt; across thread boundaries — and that's a feature, not a limitation.&lt;/p&gt;

&lt;p&gt;One small quality-of-life tip: when you need to clone an &lt;code&gt;Arc&lt;/code&gt; before moving it into a closure, use variable shadowing to keep things readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// new `a` scoped to this block&lt;/span&gt;
    &lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// original `a` still lives here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ One important constraint: &lt;code&gt;Arc&amp;lt;T&amp;gt;&lt;/code&gt; gives you shared read access — like a &lt;code&gt;&amp;amp;T&lt;/code&gt;. You &lt;strong&gt;cannot mutate&lt;/strong&gt; through it. If you want shared &lt;em&gt;and&lt;/em&gt; mutable, you need a &lt;code&gt;Mutex&lt;/code&gt;. More on that shortly.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Interior Mutability — Bending the Rules, Safely
&lt;/h2&gt;

&lt;p&gt;Here's something that trips people up early on: in Rust, a shared reference (&lt;code&gt;&amp;amp;T&lt;/code&gt;) means immutable by default. But what if you &lt;em&gt;need&lt;/em&gt; to mutate something that's shared?&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;interior mutability&lt;/strong&gt; comes in. It's not a hack — it's a principled part of the language. The trick is reframing how you think about references:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;amp;T&lt;/code&gt; = &lt;strong&gt;shared&lt;/strong&gt; reference (many can exist at once)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;amp;mut T&lt;/code&gt; = &lt;strong&gt;exclusive&lt;/strong&gt; reference (only one can exist)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Interior mutability allows mutation through a &lt;em&gt;shared&lt;/em&gt; reference, as long as the type enforces safety rules of its own. Here's the full lineup:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Thread-safe&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Cell&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Copy in / copy out&lt;/td&gt;
&lt;td&gt;Zero&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RefCell&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Runtime borrow check&lt;/td&gt;
&lt;td&gt;Small counter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Mutex&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Exclusive OS lock&lt;/td&gt;
&lt;td&gt;Blocks thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RwLock&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Shared + exclusive lock&lt;/td&gt;
&lt;td&gt;Blocks thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Atomic*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;CPU instruction&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UnsafeCell&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;⚠️&lt;/td&gt;
&lt;td&gt;Raw pointer&lt;/td&gt;
&lt;td&gt;Zero (unsafe)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every single one of these is ultimately built on &lt;code&gt;UnsafeCell&amp;lt;T&amp;gt;&lt;/code&gt; — the only legal way in Rust to mutate through a shared reference at the primitive level. The rest are safe wrappers that enforce the "no aliased mutation" rule at different points: compile time, runtime, or the hardware level.&lt;/p&gt;




&lt;h2&gt;
  
  
  Send and Sync — The Type System's Secret Weapons
&lt;/h2&gt;

&lt;p&gt;Ever wonder how Rust &lt;em&gt;actually&lt;/em&gt; prevents data races at compile time? Meet &lt;code&gt;Send&lt;/code&gt; and &lt;code&gt;Sync&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Send&lt;/code&gt;&lt;/strong&gt; means: ownership of this type can be transferred to another thread. &lt;code&gt;Arc&amp;lt;i32&amp;gt;&lt;/code&gt; is &lt;code&gt;Send&lt;/code&gt;. &lt;code&gt;Rc&amp;lt;i32&amp;gt;&lt;/code&gt; is not — because moving an &lt;code&gt;Rc&lt;/code&gt; across threads would let two threads modify the counter at the same time without synchronisation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;Sync&lt;/code&gt;&lt;/strong&gt; means: a shared reference to this type can be sent to another thread. &lt;code&gt;i32&lt;/code&gt; is &lt;code&gt;Sync&lt;/code&gt;. &lt;code&gt;Cell&amp;lt;i32&amp;gt;&lt;/code&gt; is not — its interior mutability isn't safe for concurrent access.&lt;/p&gt;

&lt;p&gt;Both traits are &lt;strong&gt;automatically derived&lt;/strong&gt;. If all your struct's fields are &lt;code&gt;Send&lt;/code&gt;, your struct is &lt;code&gt;Send&lt;/code&gt;. You don't have to think about it unless you're doing something unusual.&lt;/p&gt;

&lt;p&gt;What you &lt;em&gt;do&lt;/em&gt; get to see is the compiler error when you get it wrong:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;E0277&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;Rc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;cannot&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;sent&lt;/span&gt; &lt;span class="n"&gt;between&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="n"&gt;safely&lt;/span&gt;
   &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="py"&gt;.rs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;   &lt;span class="p"&gt;|&lt;/span&gt;     &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt;     &lt;span class="o"&gt;^^^^^^^^^^^^^&lt;/span&gt; &lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;Rc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt; &lt;span class="n"&gt;cannot&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;sent&lt;/span&gt; &lt;span class="n"&gt;between&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt; &lt;span class="n"&gt;safely&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No undefined behaviour. No race condition that only shows up in production. The mistake is caught before your code ever runs.&lt;/p&gt;




&lt;h2&gt;
  
  
  Mutexes — Finally, Shared Mutation
&lt;/h2&gt;

&lt;p&gt;You've got two threads, they share an &lt;code&gt;Arc&lt;/code&gt;, and now you want both of them to &lt;em&gt;write&lt;/em&gt; to it. This is where &lt;code&gt;Mutex&amp;lt;T&amp;gt;&lt;/code&gt; comes in.&lt;/p&gt;

&lt;p&gt;A mutex (short for &lt;em&gt;mutual exclusion&lt;/em&gt;) is simple in concept: only one thread can hold the lock at a time. Everyone else waits.&lt;/p&gt;

&lt;p&gt;What makes Rust's &lt;code&gt;Mutex&amp;lt;T&amp;gt;&lt;/code&gt; special is that &lt;strong&gt;the data lives inside the mutex&lt;/strong&gt;. You literally cannot access the data without holding the lock. Compare that to C++, where the mutex and the data it protects are completely separate — enforced only by convention and hope.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Mutex&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;guard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="nf"&gt;.lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// acquire the lock&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;guard&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                       &lt;span class="c1"&gt;// modify the data&lt;/span&gt;
&lt;span class="c1"&gt;// guard is dropped here → lock is automatically released&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's RAII at work. No &lt;code&gt;.unlock()&lt;/code&gt; call to forget. When the guard goes out of scope, the lock releases. Always.&lt;/p&gt;

&lt;p&gt;A few things to keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep locks short.&lt;/strong&gt; Holding a lock while doing slow work (sleeping, I/O) forces every other thread to wait. That's serial execution with extra steps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch out for &lt;code&gt;if let&lt;/code&gt;&lt;/strong&gt;. Unlike plain &lt;code&gt;if&lt;/code&gt;, the &lt;code&gt;if let&lt;/code&gt; pattern keeps temporaries alive for the whole body — meaning the mutex stays locked longer than you expect. Drop the guard explicitly if needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lock poisoning.&lt;/strong&gt; If a thread panics while holding a mutex, the mutex is marked "poisoned." Subsequent &lt;code&gt;.lock()&lt;/code&gt; calls return an &lt;code&gt;Err&lt;/code&gt;. Most code calls &lt;code&gt;.unwrap()&lt;/code&gt; which re-panics, propagating the failure. That's usually the right call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you have data that's read far more often than it's written, &lt;code&gt;RwLock&amp;lt;T&amp;gt;&lt;/code&gt; is the better tool — multiple readers can hold the lock simultaneously, but a writer gets exclusive access.&lt;/p&gt;




&lt;h2&gt;
  
  
  Waiting for Things to Happen
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;Mutex&lt;/code&gt; lets threads take turns accessing data. But what if a thread needs to &lt;em&gt;wait&lt;/em&gt; until the data is in a certain state — like a queue becoming non-empty?&lt;/p&gt;

&lt;p&gt;The naive approach is a busy loop: lock, check, unlock, repeat. This works but wastes CPU spinning on nothing. There are two proper solutions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Thread Parking
&lt;/h3&gt;

&lt;p&gt;For simple one-producer, one-consumer patterns, thread parking is elegant. One thread calls &lt;code&gt;thread::park()&lt;/code&gt; and goes to sleep. Another thread calls &lt;code&gt;handle.thread().unpark()&lt;/code&gt; to wake it up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Consumer thread&lt;/span&gt;
&lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="nf"&gt;.lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.pop_front&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;dbg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;park&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// nothing here, go to sleep&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Producer thread&lt;/span&gt;
&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="nf"&gt;.lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="nf"&gt;.thread&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unpark&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// wake the consumer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things worth knowing: if &lt;code&gt;unpark()&lt;/code&gt; fires &lt;em&gt;before&lt;/em&gt; &lt;code&gt;park()&lt;/code&gt; is called, the wake-up is saved — the next &lt;code&gt;park()&lt;/code&gt; returns immediately instead of sleeping. But tokens don't stack — two calls to &lt;code&gt;unpark()&lt;/code&gt; still only save one wake-up.&lt;/p&gt;

&lt;p&gt;Always re-check your condition after waking. &lt;strong&gt;Spurious wake-ups&lt;/strong&gt; are real — &lt;code&gt;park()&lt;/code&gt; can return without a matching &lt;code&gt;unpark()&lt;/code&gt;. It's rare, but your code needs to handle it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Condition Variables
&lt;/h3&gt;

&lt;p&gt;Thread parking doesn't scale. What if you have multiple consumers? You'd need to track which thread to unpark — messy.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Condvar&lt;/code&gt; is the general solution. Multiple threads can wait on the same condition variable, and any thread can wake one or all of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Condvar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Mutex&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Mutex&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;VecDeque&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;not_empty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Condvar&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Consumer&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="nf"&gt;.lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="nf"&gt;.pop_front&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;not_empty&lt;/span&gt;&lt;span class="nf"&gt;.wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// atomically: unlock → sleep → re-lock&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Producer&lt;/span&gt;
&lt;span class="n"&gt;queue&lt;/span&gt;&lt;span class="nf"&gt;.lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;not_empty&lt;/span&gt;&lt;span class="nf"&gt;.notify_one&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key magic is &lt;code&gt;condvar.wait(guard)&lt;/code&gt; — it &lt;strong&gt;atomically&lt;/strong&gt; unlocks the mutex and starts waiting. There's no gap where a notification could arrive and be silently lost. This is the thing that makes it correct.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Thread Parking&lt;/th&gt;
&lt;th&gt;Condvar&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Multiple consumers&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spurious wake-ups&lt;/td&gt;
&lt;td&gt;Possible&lt;/td&gt;
&lt;td&gt;Possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Notification before wait&lt;/td&gt;
&lt;td&gt;Safe&lt;/td&gt;
&lt;td&gt;Safe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requires Mutex&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use when&lt;/td&gt;
&lt;td&gt;Simple 1:1 wake-ups&lt;/td&gt;
&lt;td&gt;General-purpose waiting&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What You Actually Walk Away With
&lt;/h2&gt;

&lt;p&gt;Here's the honest summary of Chapter 1:&lt;/p&gt;

&lt;p&gt;Rust doesn't just give you threads — it gives you a model for thinking about &lt;em&gt;what can go wrong&lt;/em&gt; with threads and a type system that enforces the rules automatically. Data races? Impossible in safe code. Sending a non-thread-safe type across threads? Compile error. Accessing shared data without a lock? Can't happen.&lt;/p&gt;

&lt;p&gt;The primitives — &lt;code&gt;Arc&lt;/code&gt;, &lt;code&gt;Mutex&lt;/code&gt;, &lt;code&gt;Condvar&lt;/code&gt;, &lt;code&gt;Send&lt;/code&gt;, &lt;code&gt;Sync&lt;/code&gt; — aren't arbitrary. They each solve a specific, concrete problem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Arc&amp;lt;T&amp;gt;&lt;/code&gt; — shared ownership across threads&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Mutex&amp;lt;T&amp;gt;&lt;/code&gt; — shared mutation with exclusive access&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RwLock&amp;lt;T&amp;gt;&lt;/code&gt; — shared reads, exclusive writes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Condvar&lt;/code&gt; — waiting for a condition, not just a lock&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Send&lt;/code&gt; / &lt;code&gt;Sync&lt;/code&gt; — the compile-time proof that your types are thread-safe&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the foundation. Everything in the rest of the book — atomics, memory ordering, lock-free data structures — builds on exactly this.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Based on &lt;a href="https://marabos.nl/atomics/" rel="noopener noreferrer"&gt;Atomics and Locks&lt;/a&gt; by Mara Bos — highly recommended if you want to understand how concurrency actually works under the hood.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>concurrency</category>
      <category>beginners</category>
      <category>systems</category>
    </item>
  </channel>
</rss>
