mirror of
https://github.com/darkicewolf50/RustBrock.git
synced 2025-07-08 03:57:14 -06:00
started ch16.3
This commit is contained in:
@ -1 +1,72 @@
|
||||
# Shared-State Concurrency
|
||||
# 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:?}");
|
||||
}
|
||||
```
|
||||
|
Reference in New Issue
Block a user