Description
At the introduction of spawn
:
The spawn function has a very simple type signature: fn spawn(f: proc(): Send). Because it accepts only procs, and procs contain only owned data, spawn can safely move the entire proc and all its associated state into an entirely different task for execution. Like any closure, the function passed to spawn may capture an environment that it carries across tasks.
This doesn't explain what Send
means, and instead talks about a simplified concept of owning the state. Something like this would be more correct (with the old proc
closures):
The spawn function has a very simple type signature: fn spawn(f: proc():Send). A
proc
is a closure that captures its environment by value, and theSend
bound restricts it to only allow the capture of sendable types, that is data that is safe to transfer across threads. Because all captured state is sendable, the closure is as well, and spawn can safely move the entire proc and all its associated state into an entirely different task for execution.
Then later in the Arc
section, Sync
is not mentioned at all. A possible introduction could look like this:
To tackle this issue, one can use an Atomically Reference Counted wrapper (Arc) as implemented in the sync library of Rust. With an Arc, the data will no longer be copied for each task. Instead, a single copy of the data exists that can be accessed through an Arc handle (Arc). This handle is send- and clonable, which means you can make as many of them as necessary and then send them to different tasks.
However, for a given type
T
you are only allowed to construct anArc<T>
ifT
fulfills theSync
bound.Sync
is a build-in trait the expresses that a type is thread safe to access through an shared reference, that is aT
should only implementSync
if having two&T
in different threads that point to the same memory is safe. For the vast majority of types that areSync
, thread safety is given by simply not allowing any mutation through an shared reference, egu32
isShare
because you can't mutate it through an&u32
.(Remaining examples of read-only Arc usage)
Rust also enable safe mutation of data that is shared between threads, by providing library types that implement
Sync
and do some kind of runtime checking to safely pass out mutable reference one thread at a time. One example of this is theMutex<T>
type, which can be used to make any typeT
thread safe to access by using locks. For example you could construct anArc<Mutex<u32>>
to have an integer that can be shared and mutated across threads.