RustBrock/Sync and Send.md
darkicewolf50 6e94e27e06
Some checks failed
Test Gitea Actions / first (push) Successful in 17s
Test Gitea Actions / check-code (push) Failing after 15s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
finished ch16.4 and ch16
2025-03-17 15:54:52 -06:00

3.2 KiB

Extensible Concurrency with the Sync and Send Traits

The Rust language gas very few concurrency features.

Almost every feature we talked about so far has been part of the std library and not the language.

Your options for handling concurrency are not limited to the language or the std library; you are able to write your own concurrency features or use those written by others.

However, tow concurrency concepts that are embedded into the language are the std::marker traits Sync and Send.

Allowing Transference of Ownership Between Threads with Send

The marker trait Send indicates that ownership of values of the type implemented Send can be transferred between threads.

Almost every Rust type is Send.

There are some exceptions, including Rc<T>.

This cannot be be Send because if you cloned a Rc<T> value and tried to transfer ownership of the clone to another thread, both threads might update the reference count at the same time.

This is the reason, Rc<T> is implemented for use in single-threaded situations where you don't want to pay the thread-safe performance penalty.

Rust's type system and trait bounds ensure that you can never accidentally send a Rc<T> value across threads unsafely.

When we tried to do this before we got the error: the trait Send is not implemented for Rc<Mutex<i32>>.

Any type composed entirely of Send types is automatically marked as Send as well.

Almost all primitives are Send, aside form raw pointers (This will be discussed in ch20).

Allowing access form Multiple Threads with Sync

The Sync marker trait indicates that it is safe for the type implementing Sync to be referenced from multiple threads.

Any type T is Sync if &T (an immutable reference to T) is Send, meaning the reference can be sent safely to another thread.

Similar to Send, primitive types are Sync and types composed entirely of types that are Sync are also Sync.

The smart pointer Rc<T> is not Sync as well for the same reasons that it is not Send.

The RefCell<T> types (Ch15) and the family related to Cell<T> types are not Sync.

The implementation for borrow checking that RefCell<T> does at runtime is not thread-safe.

The smart pointer Mutex<T> is Sync and can be used to share access with multiple threads alike what we saw in "Sharing a Mutex<T> Between Multiple Threads" Section.

Implementing Send and Sync Manually is Unsafe

Because types that are made up of Send and Sync traits are also automatically Send and Sync, we don't need to implement these traits manually.

As marker traits they don't even have any methods to implement.

These are just useful for enforcing invariants related to concurrency.

Manually implemented these traits involves implementing unsafe Rust code (This will be discussed in Ch20).

For now the important information is that building new concurrent types not made up of Send and Sync parts requires careful thought to uphold the safety guarantees.

"The Rustonomicion" has more information about these guarantees and how to uphold them.