# Run Code Simultaneously

* Rust provides built-in support for concurrent programming through its standard library module `std::thread`.
* Threads in Rust allow multiple parts of a program to execute simultaneously, leveraging multi-core processors.

## Threads

* You can spawn threads using `std::thread::spawn`, which takes a closure, runs it in a new thread, and return `JoinHandle`.
* We can wait the spawned thread to finish using `join` method from the returned `JoinHandle`.

  > `pub fn join(self) -> Result<T>`: Waits for the associated thread to finish. This function will return immediately if the associated thread has already finished.
* We often use the `move` keyword with closures passed to `thread::spawn` because the closure will then take ownership of the values it uses from the environment, thus transferring ownership of those values from one thread to another

### Example

```rust
use std::thread;
use std::time::Duration;

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("hi number {i} from the spawned thread!");
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("hi number {i} from the main thread!");
        thread::sleep(Duration::from_millis(1));
    }

    handle.join().unwrap();
}
```

## Using Smart Pointers, Mutex, and Channels in Threads

### Shared Mutable State with Arc and Mutex

In a multi-threaded program, if we need shared mutable state, we can use:

* `Arc<T>`:
  * An atomic reference-counted smart pointer for shared ownership across threads.
* `Mutex<T>`:
  * A synchronization primitive for mutual exclusion to safely access shared data.
  * `lock()`: Acquires a lock. Blocks the thread if a lock is held.
  * `try_lock`(): Attempts to acquire a lock immediately. If lock cant be acquired, return an `Err`.

#### Example

```rust
use std::{
    sync::{Arc, Mutex},
    thread,
    time::Duration,
};

struct JobStatus {
    jobs_done: u32,
}

fn main() {
    let status = Arc::new(Mutex::new(JobStatus { jobs_done: 0 }));

    let mut handles = Vec::new();
    for _ in 0..10 {
        let status_shared = Arc::clone(&status);
        let handle = thread::spawn(move || {
            thread::sleep(Duration::from_millis(250));
            // lock and update jobs_done
            status_shared.lock().unwrap().jobs_done += 1
        });
        handles.push(handle);
    }

    // Waiting for all jobs to complete.
    for handle in handles {
        handle.join().unwrap();
    }

    println!("Jobs done: {}", status.lock().unwrap().jobs_done);
}
```

* `Arc<T>`: Enables shared ownership of the `Mutex` across threads.
* `Mutex<T>`: Ensures only one thread accesses the counter at a time.

### Multiple Readers Single Writer

\`RwLock (short for Read-Write Lock) is a synchronization primitive that allows multiple readers or a single writer to access shared data. It ensures safe concurrent access in a multi-threaded environment.

* **Multiple Readers**: Multiple threads can hold a read lock simultaneously if no thread is holding the write lock.
* **Single Writer**: Only one thread can hold the write lock, and it has exclusive access to the data.

`RwLock` is part of the `std::sync` module and is frequently used when you want to share data among threads with both read and write operations while minimizing contention.

* Read Lock
  * `read()`: Acquires a read lock. Blocks the thread if a write lock is held. Returns an immutable reference to the data.
  * `try_read()`: Attempts to acquire a read lock immediately and return `Err` if cannot acquire read lock.
* Write Lock
  * `write()`: Acquires a write lock. Blocks the thread if any read or write lock is held. Returns a mutable reference to the data.
  * `try_write()`: Attempts to acquire a write lock immediately and return `Err` if cannot acquire write lock.

#### Example

```rust

use std::{
    sync::{Arc, RwLock},
    thread,
    time::Duration,
};

struct JobStatus {
    jobs_done: u32,
}

fn main() {
    let status = Arc::new(RwLock::new(JobStatus { jobs_done: 0 }));
    let mut handles = Vec::new();

    // Write jobs
    for _ in 0..10 {
        let status_shared = Arc::clone(&status);
        let handle = thread::spawn(move || {
            thread::sleep(Duration::from_millis(250));
            // write lock and update jobs_done
            status_shared.write().unwrap().jobs_done += 1
        });
        handles.push(handle);
    }

    // Read jobs
    for _ in 0..10 {
        let status_shared = Arc::clone(&status);
        let handle = thread::spawn(move || {
            thread::sleep(Duration::from_millis(250));
            // read lock and get jobs_done
            println!("Jobs done: {}", status_shared.read().unwrap().jobs_done);
        });
        handles.push(handle);
    }

    // Waiting for all jobs to complete.
    for handle in handles {
        handle.join().unwrap();
    }
}
```

* The counter is wrapped in `Arc<RwLock<T>>` so it can be safely shared between threads.
* `Arc` provides reference counting for thread-safe ownership.
* `write()`: Acquires a write lock, granting exclusive mutable access to the shared counter.
* `read()`: Acquires a read lock, allowing multiple threads to access the counter immutably.
* The locks ensure that data races are prevented when accessing the shared counter.

### Communication Between Threads with Channels

Rust provides channels for thread communication in the `std::sync::mpsc` module:

* `mpsc`: Stands for multiple producers, single consumer.
* That means we can create multiple `Sender` using `clone` method.

#### Example

```rust
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

fn main() {
    let (tx, rx) = mpsc::channel(); // Create a channel

    // clone Sender
    let txc = tx.clone();
    // Spawn a thread to send messages
    thread::spawn(move || {
        let messages = vec![1, 2, 3, 4, 5];
        for msg in messages {
            txc.send(msg).unwrap(); // Send a message
            thread::sleep(Duration::from_millis(100));
        }
    });
    
    // Spawn a thread to send messages
    thread::spawn(move || {
        let messages = vec![6, 7, 8, 9, 10];
        for msg in messages {
            tx.send(msg).unwrap(); // Send a message
            thread::sleep(Duration::from_millis(100));
        }
    });

    // Receive messages in the main thread
    for received in rx {
        println!("Received: {}", received);
    }
}
```

* `mpsc::channel` creates a transmitter (`tx`) and a receiver (`rx`).
* Messages are sent via the Sender `tx` and received via the Receiver `rx`.

## Best Practices for Multithreading

* **Minimize Lock Contention**:
  * Keep the critical section (where the mutex is locked) as short as possible to avoid slowing down threads.
* **Use `Arc` and `Mutex` Wisely**:
  * Avoid using shared state unless necessary.
  * Prefer message passing with channels for better isolation.

## References

* <https://doc.rust-lang.org/book/ch16-00-concurrency.html>
* <https://doc.rust-lang.org/book/ch16-01-threads.html>
* <https://doc.rust-lang.org/book/ch16-02-message-passing.html>
* <https://doc.rust-lang.org/book/ch16-03-shared-state.html>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bagus-cahyono.gitbook.io/programming-notes/rust/threads.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
