#rust
- Threads can be used to split computation and run multiple tasks at the same time. Although this improves performance, it adds to complexity.
- Problems with threading include:
- Race conditions: Wherein threads attempt to access data in an inconsistent order.
- Deadlocks: Where two threads wait for each other with neither of them completing operation.
- Inconsistent bugs
- To create a new thread we call the
thread::spawn
function and pass it a closure. - By default, when the main thread of a program completes, all spawned. threads are shut down, whether or not they have finished running.
- The return type of
thread::spawn
isJoinHandle
, which when we call thejoin
method on it, will wait for its thread to finish. Therefore, theJoinHandle
from spawned threads can bejoin
ed to ensure that the threads don't end prematurely.
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("{} from spawnded thread");
}
});
for i in 1..5 {
println!("{} from the main thread");
thread::sleep(Duraton::from_millis(1));
}
handle.join().unwrap();
}
- Often, it is necessary for the spawned thread to take ownership of the value from its environment. For this, the closure passed to
spawn
can be defined withmove
, which transfers ownership of the required variables.
-
Rust has very few concurrency features that are part of the core language. However, two concurrency concepts are embedded in the language: the
std::marker
traitsSync
andSend
. -
The
Send
marker trait indicates that the ownership of values of the type implementingSend
can be transferred between threads. -
Almost every Rust type is
Send
. Any type composed entirely ofSend
types is automatically marked asSend
as well. -
One exception that was covered in the previous section is
Rc<T>
. -
The
Sync
marker trait indicates that it is safe for the type implementingSync
to be referenced from multiple threads. -
Any type
T
isSync
if&T
(an immutable reference toT
) isSend
, meaning the reference can be sent safely to another thread. -
Similar to
Send
, primitive types areSync
, and types composed entirely of types that areSync
are alsoSync
. -
The reason for having separate
Send
andSync
traits is that a type can sometimes be one, both, or neither.- The smart pointer
Rc<T>
is also neitherSend
norSync
, for reasons described above. - The
RefCell<T>
type and the family of relatedCell<T>
types areSend
(ifT: Send
), but they are notSync
. ARefCell
can be sent across a thread boundary, but not accessed concurrently because the implementation of borrow checking thatRefCell<T>
does at runtime is not thread-safe. - The smart pointer
Mutex<T>
isSend
andSync
, and can be used to share access with multiple threads. - The type
mutexguard<'a, t>
that is returned bymutex::lock
issync
(ifT: Sync
) but notSend
. It is specifically notSend
because some platforms mandate that mutexes are unlocked by the same thread that locked them.
- The smart pointer