Sync
Before we wrap up this chapter, let's talk about another key trait in Rust's standard library: Sync
.
Sync
is an auto trait, just like Send
.
It is automatically implemented by all types that can be safely shared between threads.
In order words: T
is Sync if &T
is Send
.
T: Sync
doesn't imply T: Send
It's important to note that T
can be Sync
without being Send
.
For example: MutexGuard
is not Send
, but it is Sync
.
It isn't Send
because the lock must be released on the same thread that acquired it, therefore we don't
want MutexGuard
to be dropped on a different thread.
But it is Sync
, because giving a &MutexGuard
to another thread has no impact on where the lock is released.
T: Send
doesn't imply T: Sync
The opposite is also true: T
can be Send
without being Sync
.
For example: RefCell<T>
is Send
(if T
is Send
), but it is not Sync
.
RefCell<T>
performs runtime borrow checking, but the counters it uses to track borrows are not thread-safe.
Therefore, having multiple threads holding a &RefCell
would lead to a data race, with potentially
multiple threads obtaining mutable references to the same data. Hence RefCell
is not Sync
.
Send
is fine, instead, because when we send a RefCell
to another thread we're not
leaving behind any references to the data it contains, hence no risk of concurrent mutable access.
Exercise
The exercise for this section is located in 07_threads/14_sync