From d188f8e5a48f6e86f31a3f99e1417b2691def8ca Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Fri, 10 Jan 2025 11:42:55 -0800 Subject: [PATCH 01/12] redefine parallelism/concurrency, define workers --- week10/slides.md | 61 ++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/week10/slides.md b/week10/slides.md index 3fccc95..24f34c2 100644 --- a/week10/slides.md +++ b/week10/slides.md @@ -23,72 +23,71 @@ paginate: true
+## 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 -* These terms are used (and abused) interchangably +We divide tasks among workers. -
+* In hardwareland, we call these workers **processors** or **cores**. ---- +* In softwareland, + * "Processors/CPUs" => Processes + * "Cores" => Threads -# Parallelism vs. Concurrency +* **Key difference:** Parallelism utilizes **multiple** processors/cores + * Some concurrency models don't! - + -## Parallelism - +--- - -
-## Concurrency +# Parallelism vs. Concurrency - -
- + + --- + # Parallelism vs. Concurrency (Examples)
## Parallelism +* Have one processor work on loading the webpage, while another updates the progress bar +* Processing 100x100px regions of an image on each core -- 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 +* One core * 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 From 6ea3a8a851c83b7a027f32b417bf90c0dc0e65e6 Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Fri, 10 Jan 2025 12:12:36 -0800 Subject: [PATCH 02/12] shorten pre-existing example --- week10/slides.md | 58 +++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/week10/slides.md b/week10/slides.md index 24f34c2..31a3c23 100644 --- a/week10/slides.md +++ b/week10/slides.md @@ -41,10 +41,10 @@ paginate: true We divide tasks among workers. -* In hardwareland, we call these workers **processors** or **cores**. +* In hardwareland, we call these workers **processors** and **cores**. * In softwareland, - * "Processors/CPUs" => Processes + * "Processors" => Processes * "Cores" => Threads * **Key difference:** Parallelism utilizes **multiple** processors/cores @@ -52,12 +52,14 @@ We divide tasks among workers. @@ -73,47 +75,53 @@ with "threads / processes" --- -# Parallelism vs. Concurrency (Examples) +# Parallelism vs. Concurrency: Examples
## Parallelism -* Have one processor work on loading the webpage, while another updates the progress bar -* Processing 100x100px regions of an image on each core +* 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 -* One core -* 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
+ --- # Today: Parallelism -- Threads -- Synchronization -- Message Passing -- `Send` and `Sync` -- More Synchronization +- Multithreading +- Interprocess Communication + - Shared Memory + - Synchronization + - Message Passing + - `Send` and `Sync` --- + # 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 +For this lecture, we define it as a "stream of instructions" + + --- From ddfdba58ce0df58f62b8782b9d2a985a827bd948 Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Fri, 10 Jan 2025 12:15:34 -0800 Subject: [PATCH 03/12] reorg outline --- week10/slides.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/week10/slides.md b/week10/slides.md index 31a3c23..7b553f5 100644 --- a/week10/slides.md +++ b/week10/slides.md @@ -100,11 +100,12 @@ so that this slide is shortened to --- -# Today: Parallelism +# Today - Multithreading - Interprocess Communication - Shared Memory - - Synchronization + - Data Races + - Synchronization, Atomics - Message Passing - `Send` and `Sync` @@ -112,14 +113,17 @@ so that this slide is shortened to --- -# Terminology: Threads +# Multithreading -For this lecture, we define it as a "stream of instructions" +For this lecture only, + +* **thread:** "stream of instructions" From 9ea5041667158263d95d3a2980166d7a31df9295 Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Fri, 10 Jan 2025 12:22:15 -0800 Subject: [PATCH 04/12] update multithreading --- week10/slides.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/week10/slides.md b/week10/slides.md index 7b553f5..8312b12 100644 --- a/week10/slides.md +++ b/week10/slides.md @@ -116,8 +116,8 @@ so that this slide is shortened to # Multithreading For this lecture only, - -* **thread:** "stream of instructions" +* Our workers are threads +* **Thread:** "stream of instructions" --- From c035a4b3009e407473498f8174eab3680272cb29 Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Fri, 10 Jan 2025 12:45:38 -0800 Subject: [PATCH 06/12] motivate interthread communication --- week10/slides.md | 65 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/week10/slides.md b/week10/slides.md index d358b86..7d5f753 100644 --- a/week10/slides.md +++ b/week10/slides.md @@ -102,7 +102,7 @@ so that this slide is shortened to # Today - Multithreading -- Interprocess Communication +- Interthread Communication - Shared Memory - Data Races - Synchronization, Atomics @@ -124,9 +124,68 @@ Same principles can be applied to multiprocessing Emphasize that "thread" is overloaded term --> + +--- + + +# Multithreading + +Suppose we're painting an image to the screen. + +* Divide image into eight regions + +* One region per thread + +* Easy! "Embarassingly parallel" + + + +--- + + +# Motivating Communication + +Okay, say our image is more complex. + +* We're painting circles +* Circles overlap +* The _order_ we paint circles affects their color + + + + --- -# Sharing Resources + +# Motivating Communication + +**Problem:** How do threads communicate? +* Which circles have been painted? + +**Solutions:** +* Approach 1: Shared Memory +* Approach 2: Message Passing + + + + +--- + + +# Shared Memory ```c static int x = 0; @@ -142,8 +201,6 @@ for (int i = 0; i < 20; ++i) { } ``` -* What is the value of `x` after we join on all 20 threads? - * What is the next slide's title going to be? --- From 486498b7cfdac9beacee82ec7b30674078067066 Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Fri, 10 Jan 2025 13:28:31 -0800 Subject: [PATCH 07/12] reduce pacing for data races --- week10/slides.md | 184 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 162 insertions(+), 22 deletions(-) diff --git a/week10/slides.md b/week10/slides.md index 7d5f753..9a73c9a 100644 --- a/week10/slides.md +++ b/week10/slides.md @@ -168,12 +168,23 @@ Okay, say our image is more complex. --- +# 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? -* Which circles have been painted? -**Solutions:** +**Solution:** * Approach 1: Shared Memory * Approach 2: Message Passing @@ -185,49 +196,178 @@ Okay, say our image is more complex. --- -# Shared Memory +# 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 + +`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); } ``` - --- -# 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! -# The Bad Slide | 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) | +| temp = x | | +| | temp = x | +| temp += 1 | | +| | temp += 1 | +| x = temp | | +| | x = temp | -* Uh oh... + +--- + + +# Shared Memory: Data Races + +We want `x = 2`, but we get `x = 1`! + + +| Thread 1 | Thread 2 | +|---------------|---------------| +| Read temp = 0 | | +| | Read temp = 0 | +| Set temp = 1 | | +| | Set temp = 1 | +| Set x = 1 | | +| | Set x = 1 | + + +--- + + +# Shared Memory: Data Races + +We want bolded operations to be **atomic**. + + +| Thread 1 | Thread 2 | +|---------------|---------------| +| **temp = x** | | +| | temp = x | +| **temp += 1** | | +| | temp += 1 | +| x = temp | | +| | x = temp | + + +| Thread 1 | Thread 2 | +|---------------|---------------| +| **temp = x** | | +| **temp += 1** | | +| | temp = x | +| | temp += 1 | +| x = temp | | +| | x = temp | + + --- # Synchronization From d46926f504d0a18bf8ea8d07c911cf82d23e9a6a Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Fri, 10 Jan 2025 13:32:10 -0800 Subject: [PATCH 08/12] fix formatting --- week10/slides.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/week10/slides.md b/week10/slides.md index 9a73c9a..9a10592 100644 --- a/week10/slides.md +++ b/week10/slides.md @@ -248,6 +248,8 @@ static int x = 0; # Shared Memory: Data Races +First, we have a shared variable `x`. + `x` must satisfy a property to be correct. ```c @@ -347,6 +349,26 @@ We want `x = 2`, but we get `x = 1`! We want bolded operations to be **atomic**. + + + +
+ +
+ +**Not Atomic** | Thread 1 | Thread 2 | |---------------|---------------| @@ -357,6 +379,10 @@ We want bolded operations to be **atomic**. | x = temp | | | | x = temp | +
+
+ +**Atomic** | Thread 1 | Thread 2 | |---------------|---------------| @@ -367,6 +393,9 @@ We want bolded operations to be **atomic**. | x = temp | | | | x = temp | +
+
+ --- From c211e3b021b1d42349df34df6d05fcb9badc05e9 Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Fri, 10 Jan 2025 13:47:42 -0800 Subject: [PATCH 09/12] migrate Atomics slide --- week10/slides.md | 81 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/week10/slides.md b/week10/slides.md index 9a10592..68a3c57 100644 --- a/week10/slides.md +++ b/week10/slides.md @@ -347,7 +347,7 @@ We want `x = 2`, but we get `x = 1`! # Shared Memory: Data Races -We want bolded operations to be **atomic**. +Want bolded operations to be **atomic**. + +--- + + +# 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 @@ -432,6 +461,39 @@ 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. + + + +--- + + # Threads in Rust --- @@ -926,20 +988,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" @@ -949,6 +997,7 @@ What we have gone over today is referred to as "fearless concurrency" in the rus * Subjectively, this may be the single best reason to use this language * Both parallelism and concurrency, as introduced in this lecture, benefit from these guarantees + --- # Next Lecture: Concurrency From 0f06b4ccf72c34e8949db50ab362fcc8d2c4963a Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Fri, 10 Jan 2025 13:57:10 -0800 Subject: [PATCH 10/12] migrate Message Passing slides --- week10/slides.md | 303 ++++++++++++++++++++++++++--------------------- 1 file changed, 170 insertions(+), 133 deletions(-) diff --git a/week10/slides.md b/week10/slides.md index 68a3c57..536b947 100644 --- a/week10/slides.md +++ b/week10/slides.md @@ -494,6 +494,176 @@ We can reduce words --- +# 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 +* 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); +} +``` + +--- + +# `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 --- @@ -801,142 +971,9 @@ 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); -} -``` - ---- - -# `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 {}` - - - ---- # More Shared State Primitives From 5c88ca968ae553b54be1d19b3d0e4e8d340122a5 Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Fri, 10 Jan 2025 14:40:03 -0800 Subject: [PATCH 11/12] motivate message passing --- week10/slides.md | 52 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/week10/slides.md b/week10/slides.md index 536b947..bedc110 100644 --- a/week10/slides.md +++ b/week10/slides.md @@ -153,7 +153,7 @@ Each thread retires to their cave # Motivating Communication -Okay, say our image is more complex. +Say our image is more complex. * We're painting circles * Circles overlap @@ -521,6 +521,7 @@ If we eliminate shared memory, race is trivially gone. --- + # Message Passing **Problem:** How do threads communicate? @@ -529,18 +530,58 @@ If we eliminate shared memory, race is trivially gone. - Approach 1: Shared Memory * Approach 2: Message Passing * Eliminates shared memory - + --- # Message Passing * Threads communicate via channels -* Golang famously utilizes this approach + + + + +--- + + +# 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 @@ -555,6 +596,7 @@ let (tx, rx) = mpsc::channel(); --- + # Message Passing Example ```rust @@ -572,7 +614,7 @@ println!("I am too busy to {}!", received); --- -# Message Passing Example +# Message Passing in Rust We can also use receivers as iterators! ```rust @@ -590,8 +632,10 @@ for msg in rx { ``` * 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*. From ebf6673b871009514bd3d6b1413c3cd05570b1fb Mon Sep 17 00:00:00 2001 From: Jessica Ruan Date: Fri, 10 Jan 2025 14:41:38 -0800 Subject: [PATCH 12/12] update --- week10/slides.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/week10/slides.md b/week10/slides.md index bedc110..4d7f794 100644 --- a/week10/slides.md +++ b/week10/slides.md @@ -710,6 +710,8 @@ Everything we have gone over so far is a *standard library* feature. The languag # Threads in Rust +Some implementation gotcha's + --- # Threads in Rust