rust/src/doc/nomicon/send-and-sync.md

81 lines
3.6 KiB
Markdown
Raw Normal View History

2015-07-07 09:48:57 -07:00
% Send and Sync
2015-07-14 09:56:10 -07:00
Not everything obeys inherited mutability, though. Some types allow you to
multiply alias a location in memory while mutating it. Unless these types use
synchronization to manage this access, they are absolutely not thread safe. Rust
captures this through the `Send` and `Sync` traits.
2015-07-07 09:48:57 -07:00
* A type is Send if it is safe to send it to another thread.
* A type is Sync if it is safe to share between threads (`&T` is Send).
2015-07-07 09:48:57 -07:00
2015-07-30 22:48:36 -07:00
Send and Sync are fundamental to Rust's concurrency story. As such, a
2015-07-07 09:48:57 -07:00
substantial amount of special tooling exists to make them work right. First and
foremost, they're [unsafe traits]. This means that they are unsafe to
implement, and other unsafe code can assume that they are correctly
2015-07-14 09:56:10 -07:00
implemented. Since they're *marker traits* (they have no associated items like
methods), correctly implemented simply means that they have the intrinsic
properties an implementor should have. Incorrectly implementing Send or Sync can
2015-10-13 09:44:11 -04:00
cause Undefined Behavior.
2015-07-14 09:56:10 -07:00
2015-07-30 22:48:36 -07:00
Send and Sync are also automatically derived traits. This means that, unlike
every other trait, if a type is composed entirely of Send or Sync types, then it
is Send or Sync. Almost all primitives are Send and Sync, and as a consequence
pretty much all types you'll ever interact with are Send and Sync.
2015-07-07 09:48:57 -07:00
Major exceptions include:
* raw pointers are neither Send nor Sync (because they have no safety guards).
* `UnsafeCell` isn't Sync (and therefore `Cell` and `RefCell` aren't).
* `Rc` isn't Send or Sync (because the refcount is shared and unsynchronized).
2015-07-07 09:48:57 -07:00
`Rc` and `UnsafeCell` are very fundamentally not thread-safe: they enable
2015-07-14 09:56:10 -07:00
unsynchronized shared mutable state. However raw pointers are, strictly
speaking, marked as thread-unsafe as more of a *lint*. Doing anything useful
2015-07-07 09:48:57 -07:00
with a raw pointer requires dereferencing it, which is already unsafe. In that
2015-07-14 09:56:10 -07:00
sense, one could argue that it would be "fine" for them to be marked as thread
safe.
2015-07-07 09:48:57 -07:00
However it's important that they aren't thread safe to prevent types that
2015-07-30 22:48:36 -07:00
contain them from being automatically marked as thread safe. These types have
2015-07-07 09:48:57 -07:00
non-trivial untracked ownership, and it's unlikely that their author was
necessarily thinking hard about thread safety. In the case of Rc, we have a nice
2015-07-30 22:48:36 -07:00
example of a type that contains a `*mut` that is definitely not thread safe.
2015-07-07 09:48:57 -07:00
2015-07-30 22:48:36 -07:00
Types that aren't automatically derived can simply implement them if desired:
2015-07-07 09:48:57 -07:00
```rust
struct MyBox(*mut u8);
unsafe impl Send for MyBox {}
unsafe impl Sync for MyBox {}
```
2015-07-30 22:48:36 -07:00
In the *incredibly rare* case that a type is inappropriately automatically
derived to be Send or Sync, then one can also unimplement Send and Sync:
2015-07-07 09:48:57 -07:00
```rust
2015-07-14 11:07:00 -07:00
#![feature(optin_builtin_traits)]
2015-07-30 22:48:36 -07:00
// I have some magic semantics for some synchronization primitive!
2015-07-07 09:48:57 -07:00
struct SpecialThreadToken(u8);
impl !Send for SpecialThreadToken {}
impl !Sync for SpecialThreadToken {}
```
2015-07-14 09:56:10 -07:00
Note that *in and of itself* it is impossible to incorrectly derive Send and
Sync. Only types that are ascribed special meaning by other unsafe code can
possible cause trouble by being incorrectly Send or Sync.
2015-07-07 09:48:57 -07:00
Most uses of raw pointers should be encapsulated behind a sufficient abstraction
that Send and Sync can be derived. For instance all of Rust's standard
2015-07-14 09:56:10 -07:00
collections are Send and Sync (when they contain Send and Sync types) in spite
of their pervasive use of raw pointers to manage allocations and complex ownership.
2015-07-14 09:56:10 -07:00
Similarly, most iterators into these collections are Send and Sync because they
largely behave like an `&` or `&mut` into the collection.
2015-07-07 09:48:57 -07:00
TODO: better explain what can or can't be Send or Sync. Sufficient to appeal
2015-07-14 09:56:10 -07:00
only to data races?
2015-07-30 22:48:36 -07:00
[unsafe traits]: safe-unsafe-meaning.html