22.11 Summary

Rust offers robust and safe mechanisms for concurrent programming using OS threads, leveraging its ownership and type system to prevent data races at compile time—a significant advantage compared to C and C++. This chapter covered:

  1. Core Concepts: Differentiated concurrency (structure) from parallelism (execution), and processes (isolated) from threads (shared memory). Highlighted risks like race conditions and deadlocks.
  2. Compile-Time Safety: Explained how Rust’s ownership, borrowing, and the Send/Sync marker traits prevent data races in safe code by enforcing strict access rules.
  3. OS Threads (std::thread): Introduced thread::spawn for creating threads, JoinHandle for managing them (joining, getting results, panic handling), move closures for transferring ownership, and Builder for configuration (name, stack size). Noted the 'static lifetime requirement for spawn.
  4. Data Sharing Primitives: Detailed mechanisms for safe shared access:
    • Arc<T>: For thread-safe shared ownership (atomic reference counting).
    • Mutex<T>: For synchronized, exclusive mutable access (RAII guards).
    • RwLock<T>: For allowing concurrent readers or a single writer (RAII guards).
    • Condvar: For thread synchronization based on conditions, used with Mutex.
    • Atomic Types (std::sync::atomic): For lock-free atomic operations on primitives, requiring careful memory ordering.
  5. Scoped Threads (std::thread::scope): Showcased how scoped threads lift the 'static requirement, allowing threads to safely borrow data from their parent stack frame.
  6. Message Passing (std::sync::mpsc): Presented channels (Sender/Receiver) as an alternative model based on transferring ownership of messages, avoiding direct shared state. Mentioned advanced channel crates (crossbeam-channel).
  7. Data Parallelism (rayon): Demonstrated how Rayon simplifies parallelizing computations over collections using parallel iterators (par_iter, par_iter_mut) and functions like rayon::join, managing a work-stealing thread pool automatically.
  8. SIMD (std::arch, std::simd): Introduced SIMD as instruction-level parallelism for numerical tasks, covering auto-vectorization and explicit intrinsics (platform-specific std::arch vs. safer, experimental, portable std::simd).
  9. C/C++ Comparison: Explicitly contrasted Rust’s compile-time data race prevention with the runtime risks and debugging challenges in C/C++.

Choosing the right concurrency model (OS threads for CPU-bound work, async tasks for I/O-bound work) depends on the application’s needs. Regardless of the model, Rust’s focus on safety aims to make concurrent programming more reliable and less error-prone than in traditional systems languages.