Course contentsShow
← Rust
Lesson 579 of 1,9105. Type System and TraitsFree lesson

The Send/Sync Bound for Data Races

Ensure memory safety in multi-threaded contexts through marker trait enforcement.

In this lesson, you will learn how Rust uses the Send and Sync marker traits to prevent data races at compile time, ensuring memory safety in multi-threaded code.

The Problem: Data Races

A data race occurs when two threads access the same memory location simultaneously, and at least one of those accesses is a write. In many languages, this leads to undefined behavior that is notoriously difficult to debug. Rust solves this by leveraging its type system to track which data is safe to share across thread boundaries.

The Marker Traits: Send and Sync

These are "marker traits," meaning they have no methods to implement. They simply tell the compiler about a type's capabilities:

  • Send: A type is Send if it is safe to transfer ownership of it between threads. If you move a Send type from thread A to thread B, the compiler ensures thread A can no longer access it.
  • Sync: A type is Sync if it is safe to access it from multiple threads simultaneously (i.e., it is safe to share references &T between threads).

How Rust Enforces Safety

Most primitive types in Rust (like i32 or bool) are both Send and Sync. However, types that manage their own internal memory without synchronization—like Rc<T>—are explicitly not Sync. If you try to share an Rc<T> across threads, the compiler stops you:

use std::rc::Rc;
use std::thread;

fn main() {
    let data = Rc::new(5);
    
    // This code will fail to compile!
    thread::spawn(move || {
        println!("{:?}", data);
    });
}

Because Rc<T> uses a non-atomic reference counter, it is not thread-safe. If two threads tried to update the count at the same time, the memory could be corrupted. Rust identifies this through the Send trait bound required by thread::spawn. By refusing to compile, Rust turns a potential runtime crash into a static guarantee.

When you need multi-threaded shared access, you move from Rc<T> to Arc<T> (Atomic Reference Counting), which is explicitly marked as Sync, signaling to the compiler that its internal operations are atomic and safe for concurrent use.

Key Takeaway: The Send and Sync traits act as compile-time guardrails, ensuring that only data structures explicitly designed for concurrent access can be shared between threads.