From 96dbd779e786f3801becb565ef50d91c45cbe296 Mon Sep 17 00:00:00 2001 From: darkicewolf50 Date: Thu, 13 Mar 2025 17:59:05 -0600 Subject: [PATCH] started ch16.3 --- ().md | 0 .obsidian/workspace.json | 40 ++++++++++---------- Shared State Concurrency.md | 73 ++++++++++++++++++++++++++++++++++++- 3 files changed, 92 insertions(+), 21 deletions(-) create mode 100644 ().md diff --git a/().md b/().md new file mode 100644 index 0000000..e69de29 diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index f2bc017..54a0ee1 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -24,20 +24,6 @@ { "id": "53b36d00b704136e", "type": "leaf", - "state": { - "type": "markdown", - "state": { - "file": "Smart Pointers.md", - "mode": "source", - "source": false - }, - "icon": "lucide-file", - "title": "Smart Pointers" - } - }, - { - "id": "feca3744741d15fc", - "type": "leaf", "state": { "type": "markdown", "state": { @@ -49,6 +35,20 @@ "title": "Concurrency" } }, + { + "id": "3d0ca0b1691c4c2f", + "type": "leaf", + "state": { + "type": "markdown", + "state": { + "file": "Shared State Concurrency.md", + "mode": "source", + "source": false + }, + "icon": "lucide-file", + "title": "Shared State Concurrency" + } + }, { "id": "b104e4647c0ac328", "type": "leaf", @@ -245,10 +245,14 @@ "command-palette:Open command palette": false } }, - "active": "feca3744741d15fc", + "active": "3d0ca0b1691c4c2f", "lastOpenFiles": [ - "Smart Pointers.md", "Concurrency.md", + "Shared State Concurrency.md", + "Smart Pointers.md", + "().md", + "Simultaneous Code Running.md", + "Passing Data Between Threads.md", "Leaky Reference Cycles.md", "Test Controls.md", "Ref Cell Mutability.md", @@ -270,10 +274,6 @@ "Lifetimes.md", "2025-02-04.md", "data_types.md", - "Collection of Common Data Structs.md", - "Constants.md", - "Crates.md", - "Data Types.md", "does_not_compile.svg", "Untitled.canvas", "Good and Bad Code/Commenting Pratices", diff --git a/Shared State Concurrency.md b/Shared State Concurrency.md index 7b43f58..606f164 100644 --- a/Shared State Concurrency.md +++ b/Shared State Concurrency.md @@ -1 +1,72 @@ -# Shared-State Concurrency \ No newline at end of file +# Shared-State Concurrency +Message passing is not the only way of handling concurrency. + +Another way would be multiple threads to access the same shared data. + +Consider this part of the slogan form the Go language documentation: + +"Do not communicate by sharing memory." + +What would communicating by sharing memory look like? + +Why would message-passing enthusiasts caution not to use memory sharing. + +Channels in any programming language are similar to single ownership, because once you transfer a value down a channel, you should no longer use that value. + +Shared memory concurrency is like multiple ownership: multiple threads can access the same memory location at the same time. + +As we saw before [Ch15](./Smart%20Pointers.md), where smart pointers made multiple ownership possible. + +This can add complexity because these different owners need managing. + +Rust's type system and ownership rules majority assist in getting this management correct. + +Lets look at one example mutexes, one of the more common concurrency primitives for shared memory. + +## Using Mutexes to Allow Access to Data from One Thread at a Time +*Mutex* is an abbreviation for *mutual exclusion*, as in, a mutex allows only one thread to access some data at any given time. + +To access the data in a mutex, a thread must first signal that it wants access by asking to acquire the mutex's *lock*. + +The lock is a data structure that is part of the mutex that keeps track of who is currently gas exclusive access to the data. + +The mutex can be described as *guarding* the data it holds via the locking system. + +Mutexes have an associated reputation for being difficult to use because to must remember two rules: +- You must attempt to acquire the lock before using the data +- When you are done with the data that the mutex guards, you must unlock the data so other threads can acquire the lock + +A real-world metaphor for a mutex would be like imagining a panel discussion at a conference with only one microphone. + +Before a panelist can speak, they have to ask or signal that they want to use the microphone. + +When they get the microphone, they can talk for as long as they want to and then hand the microphone to the next panelist who requests to speak. + +If a panelist forgets to hand off the microphone off when they they are finished with it, no one else is able to speak. + +If management of the shared microphone goes wrong, the panel won't work as planned. + +Management of mutexes can be incredibly tricky to get right. + +This is why so many people are enthusiastic about channels. + +However due to Rust's type system and ownership rules, you can't get locking and unlocking wrong. + +### The API of `Mutex` +Here is an example of how to use a mutex. + +We will start by using a mutex in a single threaded context. +```rust +use std::sync::Mutex; + +fn main() { + let m = Mutex::new(5); + + { + let mut num = m.lock().unwrap(); + *num = 6; + } + + println!("m = {m:?}"); +} +```