auto merge of #13070 : huonw/rust/share-doc, r=alexcrichton
std: expand the `Share` docs to make them more precise. And give some examples about exactly what's `Share` and what's not.
This commit is contained in:
commit
de4473201a
1 changed files with 45 additions and 1 deletions
|
@ -40,7 +40,51 @@ pub trait Pod {
|
|||
// Empty.
|
||||
}
|
||||
|
||||
/// Types that can be safely shared between threads, hence thread-safe.
|
||||
/// Types that can be safely shared between tasks when aliased.
|
||||
///
|
||||
/// The precise definition is: a type `T` is `Share` if `&T` is
|
||||
/// thread-safe. In other words, there is no possibility of data races
|
||||
/// when passing `&T` references between tasks.
|
||||
///
|
||||
/// As one would expect, primitive types like `u8` and `f64` are all
|
||||
/// `Share`, and so are simple aggregate types containing them (like
|
||||
/// tuples, structs and enums). More instances of basic `Share` types
|
||||
/// include "immutable" types like `&T` and those with simple
|
||||
/// inherited mutability, such as `~T`, `Vec<T>` and most other
|
||||
/// collection types. (Generic parameters need to be `Share` for their
|
||||
/// container to be `Share`.)
|
||||
///
|
||||
/// A somewhat surprising consequence of the definition is `&mut T` is
|
||||
/// `Share` (if `T` is `Share`) even though it seems that it might
|
||||
/// provide unsynchronised mutation. The trick is a mutable reference
|
||||
/// stored in an aliasable reference (that is, `& &mut T`) becomes
|
||||
/// read-only, as if it were a `& &T`, hence there is no risk of a data
|
||||
/// race.
|
||||
///
|
||||
/// Types that are not `Share` are those that have "interior
|
||||
/// mutability" in a non-thread-safe way, such as `Cell` and `RefCell`
|
||||
/// in `std::cell`. These types allow for mutation of their contents
|
||||
/// even when in an immutable, aliasable slot, e.g. the contents of
|
||||
/// `&Cell<T>` can be `.set`, and do not ensure data races are
|
||||
/// impossible, hence they cannot be `Share`. A higher level example
|
||||
/// of a non-`Share` type is the reference counted pointer
|
||||
/// `std::rc::Rc`, because any reference `&Rc<T>` can clone a new
|
||||
/// reference, which modifies the reference counts in a non-atomic
|
||||
/// way.
|
||||
///
|
||||
/// For cases when one does need thread-safe interior mutability,
|
||||
/// types like the atomics in `std::sync` and `Mutex` & `RWLock` in
|
||||
/// the `sync` crate do ensure that any mutation cannot cause data
|
||||
/// races. Hence these types are `Share`.
|
||||
///
|
||||
/// Users writing their own types with interior mutability (or anything
|
||||
/// else that is not thread-safe) should use the `NoShare` marker type
|
||||
/// (from `std::kinds::marker`) to ensure that the compiler doesn't
|
||||
/// consider the user-defined type to be `Share`. Any types with
|
||||
/// interior mutability must also use the `std::ty::Unsafe` wrapper
|
||||
/// around the value(s) which can be mutated when behind a `&`
|
||||
/// reference; not doing this is undefined behaviour (for example,
|
||||
/// `transmute`-ing from `&T` to `&mut T` is illegal).
|
||||
#[lang="share"]
|
||||
pub trait Share {
|
||||
// Empty
|
||||
|
|
Loading…
Reference in a new issue