In this lesson, you will learn how Rust uses Send and Sync marker traits to verify that your data is safe to move or share between threads.
In concurrent programming, data races are a constant threat. Rust solves this at compile time by using two special "marker traits": Send and Sync. These traits don't have any methods; they exist purely to communicate capabilities to the compiler.
What are Send and Sync?
Send: A type isSendif it is safe to move ownership of it to another thread. Most Rust types areSendby default, such asi32orString, because they own their data and moving them is safe.Sync: A type isSyncif it is safe to be referenced by multiple threads at the same time. Specifically, a typeTisSyncif and only if&TisSend.
Why verify thread safety?
Some types are fundamentally unsafe to share across threads. A classic example is Rc<T> (Reference Counted pointer). Because Rc<T> updates its reference count internally without using atomic operations, if you moved it to another thread, two threads could try to increment the count simultaneously, leading to memory corruption.
If you try to move an Rc<T> into a thread, the compiler checks the Send marker. Since Rc<T> is not Send, the compiler will stop you:
use std::rc::Rc;
use std::thread;
let data = Rc::new(5);
thread::spawn(move || {
// This will cause a compile error because Rc is not Send
println!("{:?}", data);
});
The compiler identifies that you are attempting to cross a "concurrency boundary" with a type that hasn't promised it is thread-safe. By enforcing these markers, Rust guarantees that data races are impossible for these types. When you create your own complex structures, Rust automatically derives these traits for you if all your fields are Send or Sync. You only need to think about them deeply when you are building low-level primitives or wrapping pointers in unsafe code.
Key Takeaway: The Send and Sync marker traits act as compile-time guardrails that prevent thread-unsafe data from being moved or shared across threads.