A piece of parallel computing code

What can you learn from this piece of code?

Send and Sync

Send: a value of this type can be moved to another thread safely.

Sync: a value of this type can be shared between threads by reference safely.
Formally: T: Sync means &T: Send.

Send

A type can be safely transferred (moved) from one thread to another.

What kinds of types are Send?
✅ Automatically Send (most types)

Rust has auto traits, and Send is one of them.

A type is Send automatically if all of its components are Send.

Examples:

  • Primitive types: i32, bool, f64
  • Owned heap data: Vec<T>, String, Box<T> (if T: Send)
  • Structs/enums made only of Send fields

What must be true about a type so Rust considers it safe to transfer to another thread?

A type is Send iff moving it to another thread cannot create two unsynchronized mutable accesses to the same memory.

a value may internally contain hidden shared state.

Rust guarantees memory safety even across threads, so when you move something to another thread, Rust must be sure:

After the move, the old thread cannot still access the same underlying memory.

If it could → data race → undefined behavior.

Why some types are NOT Send


1) Rc<T> — NOT Send

Rc = reference counted pointer (single-threaded)

Internally:

Rc<T> {
    refcount: usize  // shared mutable counter
    data: T
}

When you clone an Rc, two owners share the same counter.

If you move one clone to another thread:

Thread A:

drop(rc)
refcount -= 1

Thread B:

drop(rc)
refcount -= 1

Those are unsynchronized writes to the same memory location.

Boom: data race.

So Rust marks:

Rc<T>: !Send

This is exactly the situation Send prevents.

Rc is designed for single thread. if multi thread, one should use Arc<T>

2) Arc<T> — IS Send

Arc is the thread-safe version.

It uses:

AtomicUsize

instead of usize.

Atomic operations synchronize memory across threads.

So moving an Arc<T> to another thread is safe.

Therefore:

Arc<T>: Send

Fn(T) means f is a function can be called, a closure. 
FnMut is a function that has internal state might change, for example:
let mut f = |x| {
counter += 1;
x + counter
};


The internal state counter changes.

Leave a Reply

Your email address will not be published. Required fields are marked *