In this lesson, you will learn how the Send and Sync traits act as "safety markers" that tell the Rust compiler whether your data is safe to share across thread boundaries.
The Thread-Safety Contracts
When we talk about concurrency in Rust, the compiler needs to know if a piece of data can be moved to another thread or accessed by multiple threads simultaneously. Because Rust’s borrowing rules are so strict, it uses two special marker traits to enforce thread safety:
Send: A type isSendif it is safe to transfer ownership of it to another thread. Most types in Rust areSend, but things likeRc<T>are not, because their internal reference counting isn't thread-safe.Sync: A type isSyncif it is safe to access it from multiple threads through shared references (&T). A type is onlySyncif&TisSend.
How References Relate to Bounds
You might wonder why we worry about this when using borrowed references. Think of a borrowed reference like &T as a "permission to look."
If you have a function that spawns a thread and tries to move a reference into it, the compiler checks the trait bounds of the data you are passing. If your type is not Sync, you cannot safely create a shared reference (&T) that multiple threads can look at, because multiple threads could try to modify that data simultaneously, violating Rust’s core borrowing guarantees.
Consider this example:
fn process_data<T: Sync>(data: &T) {
// Because T is Sync, we are guaranteed that
// multiple threads can safely hold &T simultaneously.
std::thread::spawn(move || {
println!("{:?}", data);
});
}
If you tried to pass a type that wasn't Sync into this function, the compiler would stop you. It knows that the thread could cause a "data race" if the underlying type isn't designed to handle concurrent access.
By requiring Sync on borrowed references in multi-threaded contexts, Rust ensures that your program remains free of data races at compile time. You don't have to write these traits yourself; the compiler automatically implements them for your types if all their fields are already Send or Sync.
Key Takeaway: Send allows ownership to move between threads, while Sync allows multiple threads to safely hold shared references to the same data.