Welcome back to CodeYourCraft! Today, we're diving deep into a crucial concept in Rust: Shared State. We'll learn about Mutex and Arc, two powerful tools to manage concurrent access to shared data without causing chaos.
Shared state refers to the situation when multiple parts of a program access and modify a single piece of data. This can lead to unexpected results if not handled properly, especially in concurrent and parallel programming.
š” Pro Tip: Concurrent programming allows multiple tasks to run concurrently, while parallel programming executes multiple tasks at the same time.
In Rust, shared state can be a dangerous beast. To tame it, we use Mutex and Arc.
Mutex (short for Mutual Exclusion) ensures that only one task can access a shared state at a time, thus preventing data races.Arc (short for Atomic Reference Count) allows multiple tasks to access a shared state, but with a unique copy of the data for each task.Let's create a simple Mutex example.
use std::sync::Mutex;
let data = Mutex::new(5);In the above code, data is a Mutex holding an integer value 5.
š Note: The std::sync module contains all the synchronization primitives in Rust, including Mutex.
To access a Mutex, we use the lock method. This method returns a MutexGuard that we can use to read or modify the shared data.
let mut guard = data.lock().unwrap();
let value = *guard;In the above code, we first lock the Mutex and get a MutexGuard. Then, we read the shared data value from the MutexGuard.
Now, let's create an Arc.
use std::sync::Arc;
let data = Arc::new(5);In the above code, data is an Arc holding an integer value 5.
š Note: The std::sync module also contains Arc.
Unlike a Mutex, we can freely clone an Arc.
let other_data = data.clone();In the above code, we clone the Arc into other_data.
We can wrap an Arc inside a Mutex to share a single piece of data across multiple tasks while ensuring mutual exclusion.
let data = Arc::new(Mutex::new(5));
let mut data2 = data.clone();
let handle1 = thread::spawn(move || {
let guard = data.lock().unwrap();
*guard += 10;
});
let handle2 = thread::spawn(move || {
let guard = data2.lock().unwrap();
*guard += 15;
});
handle1.join().unwrap();
handle2.join().unwrap();
let guard = data.lock().unwrap();
let value = *guard;
println!("The shared value is: {}", value);In the above code, we create two threads that access the shared data via the wrapped Arc and Mutex. Each thread increments the shared data. After both threads finish their work, we print the final shared value.
What does the `std::sync` module contain in Rust?
That's all for today! Remember to practice using Mutex and Arc in your projects to manage shared state effectively in Rust. See you in the next tutorial! šÆ