# Fearless Concurrency - Concurrency -> Parts of a program execute independently - Parallelism -> Parts of a program execute at the same time It is hard - Not in Rust # Using Threads to Run Code Simultaneously Program = 1 Process System can execute multiple processes Why can't program execute multiple processes then? They can, but is more complex: - Race Conditions : Multiple threads accessing the same data - DeadLocks : Threads waiting on each other to finish using a resource - Esoteric and hard to replicate bugs... Thread creation differ per language: - OS Threads - 1:1 Threads -> 1 Thread created in language = 1 Operating System thread that executes - Green Threads - M:N Threads -> Any number of threads created in Language, execute in an arbitrary uncontrolled number of OS Threads. Also known as fibers, as threads will be more versatile. Rust implements 1:1 by itself, because it relies on being "small" in binary size - its runtime (the library that is compiled minimally to allow the code to run) is very small. ## Creating new Threads - `spawn` ```rust use std::thread; use std::time::Duration; fn main() { // Create 1 thread that executes the following closure thread::spawn(|| { for i in 1..10 { println!("hi number {} from the spawned thread!", i); thread::sleep(Duration::from_millis(1)); } }); // Thread spawn ends and main continues executing for i in 1..5 { println!("hi number {} from the main thread!", i); thread::sleep(Duration::from_millis(1)); } } // When execution of main ends, spawned thread is also killed as it is dependent on it ``` ### Waiting for threads to end - `join` ```rust let thread_handle = thread::spawn(|| {...}); handle.join().unwrap(); // Join blocks current thread andd waits for the thread to end its execution // Join returns a Result we could handle with a match expression, unwrap_or_else,... for this we let it panic with unwrap on error. ``` `join()` blocks current thread, then waits for the other thread to end its execution. It returns a `Result` If called before the `main thread loop`, then it will print all the lines form the `spawned thread loop` before executing anything, as it is blocked waiting fo `spawned` to finish executing. ### Using Move closures with threads Previously, we were able to move values into a closure that was being executed. That was because we were not changing the ownership of the data into another thread: ```rust let v = vec![1, 2, 3]; let handle = thread::spawn(|| { println!("Here's a vector: {:?}", v); }); // Imagine we dropped V here! // std::mem::drop(v); // What if thread had not yet tried accessing V? handle.join().unwrap(); ``` `println!` requires reference to `v`, so the closure borrows it. But the lifetime of the thread is unknown the the borrow, thus the lifetime of the borrow can't be inferred -> Invalid. We can add `move` before the closure to force the ownership to transfer, now it will not be valid in the main thread.