From 5794db2f7836da97f5965fee6cee5c550f7f5763 Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Tue, 1 Apr 2025 22:12:50 -0400 Subject: [PATCH 01/19] recover from https://github.com/rust-stuco/lectures/pull/43 --- week12/parallelism.md | 643 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 578 insertions(+), 65 deletions(-) diff --git a/week12/parallelism.md b/week12/parallelism.md index 9bc99f0..dde8fcc 100644 --- a/week12/parallelism.md +++ b/week12/parallelism.md @@ -25,156 +25,420 @@ code { --- + # Parallelism vs. Concurrency
+## Concurrency + +**Problem** of handling many tasks at once + + ## Parallelism -- Work on multiple tasks at the same time -- Utilizes multiple processors/cores +**Solution** of working on multiple tasks at the same time -
-
+* **Key difference:** Parallelism utilizes **multiple** workers -## Concurrency +--- -- Manage multiple tasks, but only do one thing at a time. -- Better utilizes a single processor/core -
-
-
+# Workers + +Parallelism divides tasks among workers. -* These terms are used (and abused) interchangably +* In hardwareland, we call these workers **processors** and **cores**. + +* In softwareland, + * "Processors" => Processes + * "Cores" => Threads + +* **Key difference:** Parallelism utilizes **multiple** processors/cores + * Some concurrency models don't! + + + -
--- + # Parallelism vs. Concurrency + --- -# Parallelism vs. Concurrency + +# Parallelism vs. Concurrency: Examples
## Parallelism - +* 8 cores, 8 threads +* 4 threads load the webpage, 4 threads update the progress bar
-## Concurrency +## Alternate Concurrency Model + +* 1 core, 1 thread +* When blocked on loading the webpage, update the progress bar -
+ --- -# Parallelism vs. Concurrency (Examples) -
-
-## Parallelism +# Today +- Multithreading +- Interthread Communication + - Shared Memory + - Data Races + - Synchronization, Atomics + - Message Passing + - `Send` and `Sync` -- Have one processor work on loading the webpage, while another updates the progress bar -* Often used to divide tasks into smaller units that can run at the same time - * e.g. Processing 100x100px regions of an image on each core - * "Divide and conquer" -
-
+--- -## Concurrency -* As we load a webpage, take a break sometimes to update the loading progress bar -* Often used to do other things while we wait for blocking I/O operations - * e.g. Running garbage collection while we wait for a response over the network +# Multithreading + +For this lecture only, +* Our workers are threads +* **Thread:** "stream of instructions" + + -
-
--- -# Today: Parallelism -- Threads -- Synchronization -- Message Passing -- `Send` and `Sync` -- More Synchronization +# Multithreading + +Suppose we're painting an image to the screen. + +* Divide image into eight regions + +* One region per thread + +* Easy! "Embarassingly parallel" + + --- -# Terminology: Threads -* Dangerously overloaded term—can mean one of many things -* For this lecture, we define it as a "stream of instructions" -* In Rust, language threads are 1:1 with OS threads -* **Key point:** Threads share the same resources +# Motivating Communication + +Say our image is more complex. + +* We're painting circles +* Circles overlap +* The _order_ we paint circles affects their color + + + --- -# Sharing Resources + +# Motivating Communication + +Now threads need to talk to each other! + +* For each pixel + * How many circles have been drawn? + * Do _not_ paint this pixel until previous circles are done + + +--- + + +# Motivating Communication + +**Problem:** How do threads communicate? + +**Solution:** +* Approach 1: Shared Memory +* Approach 2: Message Passing + + + + +--- + + +# Approach 1: Shared Memory + +For each pixel, +* Create shared variable `x` +* Increment `x` when thread touches pixel ```c static int x = 0; +``` -static void thread(void) { - int temp = x; - temp += 1; - x = temp; +Now threads know +* How many circles have been drawn? + + +--- + + +# Shared Memory: Data Races + +Are we done? + +Not quite... + +* Shared memory is ingredient for **data races** +* Let's illustrate + + + +--- + + +# Shared Memory: Data Races + +First, we have a shared variable `x`. + +```c +static int x = 0; +``` + + + + +--- + + +# Shared Memory: Data Races + +First, we have a shared variable `x`. + +`x` must satisfy a property to be correct. + +```c +// x is # of times *any* thread has called `update_x` +static int x = 0; +``` + + +--- + + +# Shared Memory: Data Races + +Second, `x` becomes incorrect mid-update. + +```c +// x is # of times *any* thread has called `update_x` +static int x = 0; + +static void update_x(void) { + int temp = x; // <- x is INCORRECT + temp += 1; // <- x is INCORRECT + x = temp; // <- x is CORRECT +} +``` + + +--- + + +# Shared Memory: Data Races + +Third, when multiple threads update at once... + +```c +// x is # of times *any* thread has called `update_x` +static int x = 0; + +static void update_x(void) { + int temp = x; // <- x is INCORRECT + temp += 1; // <- x is INCORRECT + x = temp; // <- x is CORRECT } // for (int i = 0; i < 20; ++i) { - create_thread(thread); // helper function not shown + create_thread(update_x); } ``` -* What is the value of `x` after we join on all 20 threads? - * What is the next slide's title going to be? - --- -# Race Conditions -When multiple threads have access to the same data, things get complicated... -* Specifically, this is about *data races* + +# Shared Memory: Data Races + +Third, when multiple threads update at once...they interleave! + + +| Thread 1 | Thread 2 | +|---------------|---------------| +| temp = x | | +| | temp = x | +| temp += 1 | | +| | temp += 1 | +| x = temp | | +| | x = temp | + + + + --- -# The Bad Slide + +# Shared Memory: Data Races + +We want `x = 2`, but we get `x = 1`! + | Thread 1 | Thread 2 | |---------------|---------------| -| temp = x (temp = 0) | | -| | temp = x (temp = 0) | -| temp += 1 (temp = 0 + 1) | | -| | temp += 1 (temp = 0 + 1) | -| x = temp (x = 1) | | -| | x = temp (x = 1) | +| Read temp = 0 | | +| | Read temp = 0 | +| Set temp = 1 | | +| | Set temp = 1 | +| Set x = 1 | | +| | Set x = 1 | + + +--- + -* Uh oh... +# Shared Memory: Data Races + +Want bolded operations to be **atomic**. + + + + +
+ +
+ +**Not Atomic** + +| Thread 1 | Thread 2 | +|---------------|---------------| +| **temp = x** | | +| | temp = x | +| **temp += 1** | | +| | temp += 1 | +| x = temp | | +| | x = temp | + +
+
+ +**Atomic** + +| Thread 1 | Thread 2 | +|---------------|---------------| +| **temp = x** | | +| **temp += 1** | | +| | temp = x | +| | temp += 1 | +| x = temp | | +| | x = temp | + +
+
+ + +--- + + +# Fixing a Data Race + +We must eliminate one: +1. `x` is shared +2. `x` becomes incorrect mid-update +3. Unsynchronized updates --- + +# Fixing a Data Race + +**Approach 1: Synchronization** + +Take turns! No "cutting in" mid-update. + +1. `x` is shared +2. `x` becomes incorrect mid-update +3. ~~Unsynchronized updates~~ + + +--- + + # Synchronization -To make sure instructions happen in a reasonable order, we need to establish *mutual exclusion*, so that threads don't interfere with each other. +We need to establish *mutual exclusion*, so that threads don't interfere with each other. * Mutual exclusion means "Only one thread can do something at a time" * A common tool for this is a mutex lock @@ -205,8 +469,257 @@ static void thread(void) { --- + +# Fixing a Data Race + +**Approach 2: Atomics** + +One airtight update! Cannot be "incorrect" mid-update. + +1. `x` is shared +2. ~~`x` becomes incorrect mid-update~~ +3. Unsynchronized updates + + +--- + + +# Atomics + +Rust provides atomic primitive types, like `AtomicBool`, `AtomicI8`, `AtomicIsize`, etc. +* Safe to share between threads (implementing `Sync`), providing ways to access the values atomically from any thread +* 100% lock free, using bespoke assembly instructions +* Highly performant, but very difficult to use +* Requires an understanding of *memory ordering*—one of the most difficult topics in computer systems +* We won't cover it further in this course, but the API is largely 1:1 with the C++20 atomics. + + + +--- + + +# Fixing a Data Race + +**Approach 3: No Shared Memory** + +If we eliminate shared memory, + +1. ~~`x` is shared~~ +2. `x` becomes incorrect mid-update +3. Unsynchronized updates + + +--- + + +# Fixing a Data Race + +**Approach 3: No Shared Memory** + +If we eliminate shared memory, race is trivially gone. + +1. ~~`x` is shared~~ +2. ~~`x` becomes incorrect mid-update~~ +3. ~~Unsynchronized updates~~ + + +--- + + +# Message Passing + +**Problem:** How do threads communicate? + +**Solution:** +- Approach 1: Shared Memory +* Approach 2: Message Passing + * Eliminates shared memory + + +--- + +# Message Passing + +* Threads communicate via channels + + + + +--- + + +# Approach 2: Message Passing + +Previously, shared memory solution was + +> For each pixel, +> - Create shared variable `x` +> - Increment `x` when thread touches pixel + + +--- + + +# Approach 2: Message Passing + +In message passing, we eliminate shared memory, + +For each pixel, +- Create a counter `x` for each thread +> - Increment `x` when thread touches pixel + + +--- + + +# Approach 2: Message Passing + +We broadcast updates to other threads via **message passing**. + +For each pixel, +- Create a counter `x` for each thread +- Increment `x` when thread touches pixel + * Send message to other threads + * So they update their copies of `x` + + +--- + + +# Message Passing Example + +```rust +let (tx, rx) = mpsc::channel(); +``` +* Channels have two halves, a transmitter and a receiver +* Connor writes "Review the ZFOD PR" on a rubber duck and it floats down the river (transmitter) + * Ben finds the duck downstream, and reads the message (receiver) +* Note that communication is one-way here +* Note also that each channel can only transmit/receive one type + * e.g. `Sender`, `Receiver` can't transmit integers + +--- + + +# Message Passing Example + +```rust +let (tx, rx) = mpsc::channel(); + +thread::spawn(move || { // Take ownership of `tx` + let val = String::from("review the ZFOD PR!"); + tx.send(val).unwrap(); // Send val through the transmitter +}); + +let received = rx.recv().unwrap(); // receive val through the receiver +println!("I am too busy to {}!", received); +``` +* Note that, after we send `val`, we no longer have ownership of it! + +--- + +# Message Passing in Rust +We can also use receivers as iterators! + +```rust +let (tx, rx) = mpsc::channel(); + +thread::spawn(move || { // Take ownership of `tx` + let val = String::from("review the ZFOD PR!"); + tx.send(val).unwrap(); // Send val through the transmitter + tx.send("buy Connor lunch".into()).unwrap(); +}); + +for msg in rx { + println!("I am too busy to {}!", msg); +} +``` +* Wait, what does `mpsc` stand for? + + +--- + + +# `mpsc` ⟹ Multiple Producer, Single Consumer + +This means we can `clone` the transmitter end of the channel, and have *multiple producers*. + +```rust +let (tx, rx) = mpsc::channel(); + +let tx1 = tx.clone(); +thread::spawn(move || { // owns tx1 + tx1.send("yo".into()).unwrap(); + thread::sleep(Duration::from_secs(1)); +}); + +thread::spawn(move || { // owns tx + tx.send("hello".into()).unwrap(); + thread::sleep(Duration::from_secs(1)); +}); + +for received in rx { + println!("Got: {}", received); +} +``` + +--- + +# `Send` and `Sync` + +--- + +# `Send` and `Sync` + +Everything we have gone over so far is a *standard library* feature. The language itself provides two marker traits to enforce safety when dealing with multiple threads, `Send` and `Sync`. + + + + +--- + +# `Send` vs. `Sync` + + +## `Send` + +* Indicates that the type is safe to *send* between threads. +* `Rc` does not implement this trait, because it is not thread safe. + + +## `Sync` + +* Indicates that the type implementing `Send` can be referenced from multiple threads +* For example, `RefCell` from last lecture implements `Send` but not `Sync` +* `Rc` does not implement `Sync` either + + + + +--- + +# Using `Send` and `Sync` +* It is generally rare that you would implement these traits yourself + * Structs containing all `Send`/`Sync` types automatically derive `Send`/`Sync` + * Explicitly implementing either one requires using `unsafe` +* This would be an example of a trait you might want to *unimplement* + * e.g. If you are doing something with `unsafe` that is not thread-safe + * `impl !Send for CoolType {}` + + + + +--- + + # Threads in Rust +Some implementation gotcha's + --- # Threads in Rust From f5664ae0ee00dd42c461d5dea86d036a059bf962 Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Tue, 1 Apr 2025 23:17:18 -0400 Subject: [PATCH 02/19] dedup --- week12/parallelism.md | 197 ++++++++---------------------------------- 1 file changed, 36 insertions(+), 161 deletions(-) diff --git a/week12/parallelism.md b/week12/parallelism.md index dde8fcc..8a823f3 100644 --- a/week12/parallelism.md +++ b/week12/parallelism.md @@ -123,7 +123,7 @@ so that this slide is shortened to # Multithreading -For this lecture only, +For this lecture only... * Our workers are threads * **Thread:** "stream of instructions" @@ -136,6 +136,24 @@ Emphasize that "thread" is overloaded term --- +# Example: Creating a Thread +Threads can be created ("spawned") using `thread::spawn`. +```rust +let handle = thread::spawn(|| { + for i in 1..10 { + println!("hi number {} from the spawned thread!", i); + thread::sleep(Duration::from_millis(1)); + } +}); +``` +* `thread::spawn` takes a function as argument + * This is the function that the thread runs +* We can spawn multiple of these, to run multiple functions at once! + + +--- + + # Multithreading Suppose we're painting an image to the screen. @@ -164,7 +182,7 @@ Each thread retires to their cave Say our image is more complex. * We're painting circles -* Circles overlap +* Circles overlap and constantly moving * The _order_ we paint circles affects their color --- @@ -669,56 +681,22 @@ for received in rx { --- -# `Send` and `Sync` - ---- - -# `Send` and `Sync` - -Everything we have gone over so far is a *standard library* feature. The language itself provides two marker traits to enforce safety when dealing with multiple threads, `Send` and `Sync`. - - - - ---- - -# `Send` vs. `Sync` - - -## `Send` - -* Indicates that the type is safe to *send* between threads. -* `Rc` does not implement this trait, because it is not thread safe. - - -## `Sync` -* Indicates that the type implementing `Send` can be referenced from multiple threads -* For example, `RefCell` from last lecture implements `Send` but not `Sync` -* `Rc` does not implement `Sync` either +# Recap - +When tackling a parallelism problem, think: - ---- - -# Using `Send` and `Sync` -* It is generally rare that you would implement these traits yourself - * Structs containing all `Send`/`Sync` types automatically derive `Send`/`Sync` - * Explicitly implementing either one requires using `unsafe` -* This would be an example of a trait you might want to *unimplement* - * e.g. If you are doing something with `unsafe` that is not thread-safe - * `impl !Send for CoolType {}` - - +* What are my workers and how many do I have? +* How should I divide the work among my workers? +* Do I need to share data between workers? + * Shared Memory vs Message Passing --- - # Threads in Rust -Some implementation gotcha's +Now that we have an framework for parallelism problems, let's dive into the Rust specifics! --- @@ -1025,95 +1003,6 @@ println!("Final value of x: {}", *x.lock().unwrap()); * `x` is 20, *every time*. * And it is illegal for it to be anything else in safe Rust. ---- - -# Parallelism Checkpoint -Up until now, we have been talking about parallelism with *shared state*. Let's shift gears and talk about *message passing*. - ---- - -# Message Passing - -Rather than sharing state between threads, an increasingly popular approach to safe concurrency is message passing. -* In this approach, threads communicate with each other through channels -* Golang famously utilizes this approach - - ---- - -# Message Passing Example - -```rust -let (tx, rx) = mpsc::channel(); -``` -* Channels have two halves, a transmitter and a receiver -* Connor writes "Review the ZFOD PR" on a rubber duck and it floats down the river (transmitter) - * Ben finds the duck downstream, and reads the message (receiver) -* Note that communication is one-way here -* Note also that each channel can only transmit/receive one type - * e.g. `Sender`, `Receiver` can't transmit integers - ---- - -# Message Passing Example - -```rust -let (tx, rx) = mpsc::channel(); - -thread::spawn(move || { // Take ownership of `tx` - let val = String::from("review the ZFOD PR!"); - tx.send(val).unwrap(); // Send val through the transmitter -}); - -let received = rx.recv().unwrap(); // receive val through the receiver -println!("I am too busy to {}!", received); -``` -* Note that, after we send `val`, we no longer have ownership of it! - ---- - -# Message Passing Example -We can also use receivers as iterators! - -```rust -let (tx, rx) = mpsc::channel(); - -thread::spawn(move || { // Take ownership of `tx` - let val = String::from("review the ZFOD PR!"); - tx.send(val).unwrap(); // Send val through the transmitter - tx.send("buy Connor lunch".into()).unwrap(); -}); - -for msg in rx { - println!("I am too busy to {}!", msg); -} -``` -* Wait, what does `mpsc` stand for? - ---- - -# `mpsc` ⟹ Multiple Producer, Single Consumer - -This means we can `clone` the transmitter end of the channel, and have *multiple producers*. - -```rust -let (tx, rx) = mpsc::channel(); - -let tx1 = tx.clone(); -thread::spawn(move || { // owns tx1 - tx1.send("yo".into()).unwrap(); - thread::sleep(Duration::from_secs(1)); -}); - -thread::spawn(move || { // owns tx - tx.send("hello".into()).unwrap(); - thread::sleep(Duration::from_secs(1)); -}); - -for received in rx { - println!("Got: {}", received); -} -``` --- @@ -1212,20 +1101,6 @@ thread::spawn(move || { --- -# One more thing... - ---- - -# `std::sync::atomic` - -Rust provides atomic primitive types, like `AtomicBool`, `AtomicI8`, `AtomicIsize`, etc. -* Safe to share between threads (implementing `Sync`), providing ways to access the values atomically from any thread -* 100% lock free, using bespoke assembly instructions -* Highly performant, but very difficult to use -* Requires an understanding of *memory ordering*—one of the most difficult topics in computer systems -* We won't cover it further in this course, but the API is largely 1:1 with the C++20 atomics. - ---- # Review: "Fearless Concurrency" From 900a2ba801657251a398f28fbcfd61d46ff1d6c1 Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Wed, 2 Apr 2025 00:01:10 -0400 Subject: [PATCH 03/19] discuss lock-free vs lock-based, address comments --- week12/parallelism.md | 89 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 15 deletions(-) diff --git a/week12/parallelism.md b/week12/parallelism.md index 8a823f3..0821743 100644 --- a/week12/parallelism.md +++ b/week12/parallelism.md @@ -110,7 +110,7 @@ so that this slide is shortened to # Today - Multithreading -- Interthread Communication +- Inter-thread Communication - Shared Memory - Data Races - Synchronization, Atomics @@ -159,10 +159,8 @@ let handle = thread::spawn(|| { Suppose we're painting an image to the screen. * Divide image into eight regions - -* One region per thread - -* Easy! "Embarassingly parallel" +* Assign each thread to paint one region +* Easy! "Embarassingly parallel" - threads don't need to keep tabs on each other + + +--- + + # Atomics Rust provides atomic primitive types, like `AtomicBool`, `AtomicI8`, `AtomicIsize`, etc. @@ -687,7 +746,7 @@ for received in rx { When tackling a parallelism problem, think: * What are my workers and how many do I have? -* How should I divide the work among my workers? +* How to divide the work among workers * Do I need to share data between workers? * Shared Memory vs Message Passing From a5ea70050a657e09b8fe3fa3a222573e011c724e Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Thu, 3 Apr 2025 14:52:56 -0400 Subject: [PATCH 04/19] revamp first half, add diagrams --- images/week12/circle-order-A-then-B.png | Bin 0 -> 9055 bytes images/week12/circle-order-B-then-A.png | Bin 0 -> 9006 bytes week12/parallelism.md | 170 ++++++++++++------------ 3 files changed, 87 insertions(+), 83 deletions(-) create mode 100644 images/week12/circle-order-A-then-B.png create mode 100644 images/week12/circle-order-B-then-A.png diff --git a/images/week12/circle-order-A-then-B.png b/images/week12/circle-order-A-then-B.png new file mode 100644 index 0000000000000000000000000000000000000000..41ac3dbf9669eda4b149bdadc68425202cbae1fa GIT binary patch literal 9055 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 I6(P|70v+|c9{>OV literal 0 HcmV?d00001 diff --git a/images/week12/circle-order-B-then-A.png b/images/week12/circle-order-B-then-A.png new file mode 100644 index 0000000000000000000000000000000000000000..51b91f938acb9fb7d49489e8e264843879234375 GIT binary patch literal 9006 zcmeHtXH=6-*DeGIp-L};G$~3Kq)BfoT@XSKp@{;aBPG<(6r?Iax`L=cgh=lsAksxe zdI?DHNbh{N&-0#j);jC_IzP{Pe`ICu%

#duFb^XJ7a82Zr}(D6diy5fRbo+}AQ8 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 DA= --- -# Motivating Communication +# The Case for Communication Now our threads need to talk to each other! @@ -208,7 +214,7 @@ Now our threads need to talk to each other! **Problem:** How do threads communicate? -**Solution:** +**Solutions:** We'll discuss two approaches... * Approach 1: Shared Memory * Approach 2: Message Passing @@ -225,7 +231,7 @@ Now our threads need to talk to each other! For each pixel, create a shared variable `x`: ```c -static int x = 0; // one per pixel +static int x = 0; // One per pixel ``` * When a thread touches a pixel, increment the pixel's associated `x` @@ -248,6 +254,7 @@ Not quite... We'll walk through the other ingredients --> + --- @@ -271,7 +278,7 @@ static int x = 0; # Shared Memory: Data Races -First ingredient: `x` is shared, and `x` must satisfy some property to be correct. +First ingredient: `x` is in shared memory, and `x` must satisfy some property to be correct. ```c // x is # of times *any* thread has called `update_x` @@ -370,13 +377,7 @@ We want `x = 2`, but we get `x = 1`! # Shared Memory: Data Races -Want bolded operations to be **atomic**. - - +We want the read-set operations to be **atomic**. +

+ +
+ +**Not Atomic** + +| Thread 1 | Thread 2 | +|---------------|---------------| +| temp = refcount | | +| | temp = refcount | +| temp += 1 | | +| | temp += 1 | +| refcount = temp | | +| | refcount = temp | + +
+
+ +**Atomic** + +| Thread 1 | Thread 2 | +|---------------|---------------| +| temp = x | | +| temp += 1 | | +| x = temp | | +| | temp = x | +| | temp += 1 | +| | x = temp | + +
+
+ + + +--- + # `Arc` -"Arc" stands for "Atomically Reference Counted". This means, it is thread-safe, at the cost of slightly slower operations. +Arc: "**A**tomically **R**eference **C**ounted" +* Think of the refcount as atomically updated with `fetch_add` + * General advice: default to using `Rc`, and switch to `Arc` if you need to share ownership across threads * The compiler will not let you use `Rc` across threads + * `Arc` is thread-safe, at the cost of slightly slower operations --- @@ -884,44 +940,33 @@ handle.join().unwrap(); ![bg right:20% 75%](../images/ferris_does_not_compile.svg) -# Sharing Mutable Resources in Rust -If we attempt to mutate the vector, we will indeed encounter an error +# Sharing *Mutable* Resources in Rust + +However, if we introduce a write, we would have a data race: + ```rust let v = Arc::new(vec![1, 2, 3]); let v_copy = v.clone(); let handle = thread::spawn(move || { - v_copy.push(4); + v_copy.push(4); // <- added this line println!("Here's a vector: {:?}", v_copy); }); -v.push(5); +v.push(5); // <- added this line println!("Here's a vector: {:?}", v); handle.join().unwrap(); ``` -* This prevents a data race - * If we allowed this, it would violate one of the rules—only one mutable reference at a time + --- ![bg right:20% 75%](../images/ferris_does_not_compile.svg) # Sharing Mutable Resources in Rust -```rust -let v = Arc::new(vec![1, 2, 3]); - -let v_copy = v.clone(); -let handle = thread::spawn(move || { - v_copy.push(4); - println!("Here's a vector: {:?}", v_copy); -}); - -v.push(5); -println!("Here's a vector: {:?}", v); -handle.join().unwrap(); -``` +The compiler indeed stops us: ``` cannot borrow data in an Arc as mutable @@ -930,12 +975,18 @@ help: trait DerefMut is required to modify through a dereference, but it is not implemented for Arc> ``` +* Note how this check is baked into the type and traits system for `Arc` + * Rust's typechecker guarantees absence of data races! + + + --- # Sharing Mutable Resources in Rust The solution to this is actually the same as in C—we introduce a mutex. + --- # Mutexes in Rust From 4e70486571f5d32fdd06d294c958d35ce0afd5fe Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Thu, 3 Apr 2025 15:47:15 -0400 Subject: [PATCH 06/19] clean up speaker notes --- week12/parallelism.md | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/week12/parallelism.md b/week12/parallelism.md index 42515e3..4221767 100644 --- a/week12/parallelism.md +++ b/week12/parallelism.md @@ -51,7 +51,7 @@ Parallelism divides tasks among workers. * In hardwareland, we call these workers **processors** and **cores**. -* In softwareland, +* In softwareland, * "Processors" => Processes * "Cores" => Threads @@ -60,14 +60,14 @@ Parallelism divides tasks among workers. @@ -263,14 +263,10 @@ We'll walk through the other ingredients Suppose we have a shared variable `x`. ```c -// Note this is C pseudocode static int x = 0; ``` - +* This is C pseudocode; we'll explain Rust's interface in second half --- @@ -460,6 +456,8 @@ We need to establish *mutual exclusion*, so that threads don't interfere with ea + + --- From b8d1b0481113d6471cc1ea587e5b44f07ea0a550 Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Thu, 3 Apr 2025 15:56:39 -0400 Subject: [PATCH 07/19] format --- week12/parallelism.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/week12/parallelism.md b/week12/parallelism.md index 4221767..56b689b 100644 --- a/week12/parallelism.md +++ b/week12/parallelism.md @@ -51,7 +51,7 @@ Parallelism divides tasks among workers. * In hardwareland, we call these workers **processors** and **cores**. -* In softwareland, +* In softwareland... * "Processors" => Processes * "Cores" => Threads @@ -115,8 +115,8 @@ Two big questions to ask: * Who are the workers and how do we divide the work? * Inter-thread / Inter-process Communication (IPC) * What needs to be shared and how? - * Approach 1: Shared Memory - * Approach 2: Message Passing + * Approach 1: Shared Memory + * Approach 2: Message Passing --- @@ -235,7 +235,7 @@ static int x = 0; // One per pixel ``` * When a thread touches a pixel, increment the pixel's associated `x` -* Now each thread knows how many layers of paint on that pixel +* Now each thread knows how many layers of paint on that pixel has --- From 1f85f90078db77abf6810ca65e20ad2ae0b194a9 Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Sat, 5 Apr 2025 16:02:32 -0400 Subject: [PATCH 08/19] remove div --- week12/parallelism.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/week12/parallelism.md b/week12/parallelism.md index 56b689b..63b5dc4 100644 --- a/week12/parallelism.md +++ b/week12/parallelism.md @@ -28,9 +28,6 @@ code { # Parallelism vs. Concurrency -
-
- ## Concurrency **Problem** of handling many tasks at once From 15468ace4e61da40ec2c6a695ee2a65fbf20817d Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Sat, 5 Apr 2025 16:43:57 -0400 Subject: [PATCH 09/19] address comments --- week12/parallelism.md | 46 ++++++++++--------------------------------- 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/week12/parallelism.md b/week12/parallelism.md index 63b5dc4..98905b7 100644 --- a/week12/parallelism.md +++ b/week12/parallelism.md @@ -74,32 +74,7 @@ invisible to the programmer # Parallelism vs. Concurrency - - - ---- - - -# Parallelism vs. Concurrency: Examples -
-
- -## Parallelism - -* 8 cores, 8 threads -* 4 threads load the webpage, 4 threads update the progress bar - -
-
- -## Alternate Concurrency Model - -* 1 core, 1 thread -* When blocked on loading the webpage, update the progress bar - - -
-
+ --- @@ -110,7 +85,7 @@ invisible to the programmer Two big questions to ask: * Division of Work * Who are the workers and how do we divide the work? -* Inter-thread / Inter-process Communication (IPC) +* Thread Communication * What needs to be shared and how? * Approach 1: Shared Memory * Approach 2: Message Passing @@ -144,7 +119,7 @@ let handle = thread::spawn(|| { } }); ``` -* `thread::spawn` takes a function as argument +* `thread::spawn` takes a closure as argument * This is the function that the thread runs * We can spawn multiple of these, to run multiple functions at once @@ -159,11 +134,11 @@ Suppose we're painting an image to the screen, and we have eight threads. * How should we divide the work? * Divide image into eight regions * Assign each thread to paint one region -* Easy! "Embarassingly parallel" +* Easy! "Embarrassingly parallel" * Threads don't need to keep tabs on each other +* That is, while Thread 1 is executing its sequence of instructions, Thread 2 cannot cut in + --- @@ -599,7 +572,7 @@ If we eliminate shared memory... race is trivially gone. # Message Passing -Now we talk about the second approach to inter-thread communication: +Now we talk about the second approach to communication: - Approach 1: Shared Memory * Approach 2: Message Passing @@ -766,6 +739,7 @@ Rust uniquely provides some nice guarantees for parallel code, and at the same t --- + # Creating Threads, In More Detail Threads can be created/spawned using `thread::spawn`. ```rust @@ -776,7 +750,7 @@ let handle = thread::spawn(|| { } }); ``` -* `thread::spawn` takes in a function, implementing the `FnOnce` and `Send` traits. +* `thread::spawn` takes in a closure, implementing the `FnOnce` and `Send` traits. * More on the `Send` trait later... * Returns a `JoinHandle` type From 07bf294b5c418fccdfbd52886db4ca5816c1b1ce Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Sat, 5 Apr 2025 17:34:35 -0400 Subject: [PATCH 10/19] add more detailed example --- week12/img/concvspar-2.png | Bin 0 -> 116016 bytes week12/parallelism.md | 85 ++++++++++++++++++++++++++++++++----- 2 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 week12/img/concvspar-2.png diff --git a/week12/img/concvspar-2.png b/week12/img/concvspar-2.png new file mode 100644 index 0000000000000000000000000000000000000000..0e3a5b49d9e784a9c9b980a942254a4c69707dce GIT binary patch literal 116016 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⪚4mE$KZT;c+g_=9ceqp;C8`KAntDfRQIETm8H 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 AC;$Ke literal 0 HcmV?d00001 diff --git a/week12/parallelism.md b/week12/parallelism.md index 98905b7..91cae37 100644 --- a/week12/parallelism.md +++ b/week12/parallelism.md @@ -106,12 +106,33 @@ Emphasize that "thread" is overloaded term --> +--- + +# Example: The Main Thread + +The thread that runs by default is the main thread. + +```rust +for i in 1..5 { + println!("hi number {i} from the main thread!"); + thread::sleep(Duration::from_millis(1)); +} +``` + + --- # Example: Creating a Thread -Threads can be created ("spawned") using `thread::spawn`. + +We can create ("spawn") more threads with `thread::spawn`: + ```rust +for i in 1..5 { + println!("hi number {i} from the main thread!"); + thread::sleep(Duration::from_millis(1)); +} + let handle = thread::spawn(|| { for i in 1..10 { println!("hi number {} from the spawned thread!", i); @@ -119,9 +140,58 @@ let handle = thread::spawn(|| { } }); ``` + * `thread::spawn` takes a closure as argument * This is the function that the thread runs -* We can spawn multiple of these, to run multiple functions at once + + +--- + + +# Example: Joining Threads + +We join threads when we want to wait for a particular thread to finish execution: + +```rust +for i in 1..5 { + println!("hi number {i} from the main thread!"); + thread::sleep(Duration::from_millis(1)); +} + +let handle = thread::spawn(|| { + for i in 1..10 { + println!("hi number {} from the spawned thread!", i); + thread::sleep(Duration::from_millis(1)); + } +}); + +handle.join().unwrap(); +``` + +* Blocks the current thread until the thread associated with `handle` finishes + + +--- + + +# Example: Multithreading Output + +See how the threads are alternating, effectively counting up at once: +``` +hi number 1 from the main thread! +hi number 2 from the main thread! +hi number 1 from the spawned thread! +hi number 3 from the main thread! +hi number 2 from the spawned thread! +hi number 4 from the main thread! +hi number 3 from the spawned thread! +hi number 4 from the spawned thread! +hi number 5 from the spawned thread! +hi number 6 from the spawned thread! +hi number 7 from the spawned thread! +hi number 8 from the spawned thread! +hi number 9 from the spawned thread! +``` --- @@ -345,7 +415,7 @@ We want `x = 2`, but we get `x = 1`! # Shared Memory: Data Races -We want the read-set operations to be **atomic**. +We want the update to be **atomic**. That is, other threads cannot cut in mid-update.