Git repo: https://github.com/caveofprogramming/rust/
As programmers familiar with multithreading will know, you can’t just write to shared data using multiple different threads. Rust even stops you from doing this via its ownership system.
For example, in C (or practically any other language), even if two threads try to increment an integer, this creates problems, because even this isn’t an atomic (single step) operation.
Behind the scenes, the value of the integer gets copied to a register, incremented, and then copied back to the original memory location. Two threads doing this at the same time will sometimes both copy the original value before incrementing and copying back, and this means some increments will get skipped.
One way to deal with this is by using thread-safe integers, in this particular case. Rust has AtomicI32
for example.
Another, more general but also trickier method, is to use mutexes (locks) to ensure that two threads cannot write to the same variable at the same time.
The examples in this page are all built around the Rust documentation at https://doc.rust-lang.org/book/ch16-03-shared-state.html
A Simple Mutex Example
The new method of Mutex
expects the initial value of the type that we want to protect.
In this example, a Mutex
wraps an integer. To access the integer for writing, we have to lock the mutex.
The lock()
method returns a Result
which wraps either a MutexGuard
or a PoisonError
. MutexGuard
is a kind of smart pointer which implements the Deref
trait, so we can dereference it to get at the actual value.
The key point about a mutex is that two threads (or the same thread) cannot lock it twice at the same time.
The following program just hangs, because the main thread waits indefinitely on the second lock attempt. It’s waiting for the lock to be unlocked by another thread, which never happens.
Using Mutexes to Increment a Value
In the following program I create 10 threads and, in each of them, I increment the value guarded by the mutex.
When you try to do this naively, the first problem that comes up is you cannot access the mutex variable from the closure, because then the closure code might outlive the variable.
You are forced to add move
to the closer declaration, to move the variable into the closure. But then, you can’t move it into subsequent closures in further iterations of the loop.
You can try to fix this by using Rc
, with clone
, but then the problem is that Rc
isn’t threadsafe, so you still get an error and the code won’t compile.
However, if we swap Rc
for Arc
(atomic reference counter), which is thread safe, the code now works and finally prints 10.
Share this post