started ch16.3
Some checks failed
Test Gitea Actions / first (push) Successful in 45s
Test Gitea Actions / check-code (push) Failing after 20s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped

This commit is contained in:
darkicewolf50 2025-03-13 17:59:05 -06:00
parent 661e8bf5c7
commit 96dbd779e7
3 changed files with 92 additions and 21 deletions

0
().md Normal file
View File

View File

@ -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",

View File

@ -1 +1,72 @@
# 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<T>`
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:?}");
}
```