Threads in Rust

use std::thread;

fn main() {
    thread::spawn(f);
    thread::spawn(f);

    println!("Hello from the main thread.");
}

fn f() {
    println!("Hello from another thread!");

    let id = thread::current().id();
    println!("This is my thread id: {id:?}");
}
  • Two threads are spawned in the example from the main thread.
  • Without joining the thread, main thread could exit before the spawned thread finish.
  • t1.join().unwrap(); t2.join().unwrap() method waits until the thread has finished executing.

Scoped Threads

let numbers = vec![1, 2, 3];

thread::scope(|s| {
    s.spawn(|| {
        println!("length: {}", numbers.len());
    });
    s.spawn(|| {
        for n in &numbers {
            println!("{n}");
        }
    });
});

Scoped thread guarantees that none of the threads spawned in the scope can outlvie the scope.

  • The scoped spawn method does not have 'static bound on its argument type

Shared Onwership and Reference Counting

Borrowing and Data Races

  • Immutable borrow (&data)

    • Immutable reference can be copied.
    • Access to the data it references is shared between all copies of such a reference.
    • Compiler doesn't allow you to mutate something through this type of referece, since that might affect other coe that's currently borrowing the same data.
  • Mutable borrow (&mut data)

    • Active borrow of that data
    • Ensures that mutating the data will note change anything that other code is currently looing at.

Interior Mutability

Thread Safety: Send and Sync

Locking: Mutexes and RwLocks