mirror of
https://github.com/darkicewolf50/RustBrock.git
synced 2025-06-15 21:14:18 -06:00
73 lines
2.9 KiB
Markdown
73 lines
2.9 KiB
Markdown
# 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:?}");
|
|
}
|
|
```
|