ch16 done
This commit is contained in:
parent
62f797ae3b
commit
8d9f5104cc
7
ch16/extensible-concurrency/Cargo.lock
generated
Normal file
7
ch16/extensible-concurrency/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "extensible-concurrency"
|
||||||
|
version = "0.1.0"
|
6
ch16/extensible-concurrency/Cargo.toml
Normal file
6
ch16/extensible-concurrency/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "extensible-concurrency"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
20
ch16/extensible-concurrency/src/main.rs
Normal file
20
ch16/extensible-concurrency/src/main.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
//! # Extensible Concurrency with the `Sync` and `Send` Traits
|
||||||
|
//!
|
||||||
|
//! Two concurrency concepts embedded in the language: the std::marker
|
||||||
|
//! `Sync` and `Send`.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Allowing Transference of ownership between threads with `Send`
|
||||||
|
//
|
||||||
|
// `Send` marker traits indicates ownership of values of the
|
||||||
|
// type implementing `Send` can be transferred between threads.
|
||||||
|
// Almost every Rust type is `Send` besides `Rc<T>`.
|
||||||
|
|
||||||
|
// Allowing Access from Multiple Threads with `Sync`
|
||||||
|
//
|
||||||
|
// The `Sync` marker trait indicates it's safe for the type implementing
|
||||||
|
// `Sync` to be referenced from multiple threads.
|
||||||
|
//
|
||||||
|
// Implementing Send and Sync Manually Is Unsafe
|
||||||
|
// This doesn't exactly explain why, just says look at Chapter 20.
|
||||||
|
}
|
7
ch16/message-passing/Cargo.lock
generated
Normal file
7
ch16/message-passing/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "message-passing"
|
||||||
|
version = "0.1.0"
|
6
ch16/message-passing/Cargo.toml
Normal file
6
ch16/message-passing/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "message-passing"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
100
ch16/message-passing/src/main.rs
Normal file
100
ch16/message-passing/src/main.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
//! One way to ensure safe concurrency is message passing.
|
||||||
|
//! Threads send data between one another.
|
||||||
|
//! To accomplish message-sending concurrency, Rust
|
||||||
|
//! provides an implementation of channels. Channel
|
||||||
|
//! is generally a way for data to sent from one
|
||||||
|
//! channel to another.
|
||||||
|
//!
|
||||||
|
//! A channel has two halves: a transmitter and a reciever.
|
||||||
|
//! Channel is *closed* if either the transmitter or
|
||||||
|
//! reciever is dropped.
|
||||||
|
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// mpsc stands for multiple producer, single consumer.
|
||||||
|
// Rust can have multilple sending and only one receiving
|
||||||
|
// tx for transmitter and rx for receiver.
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
// spawned thread needs to own transmitter to send messages.
|
||||||
|
thread::spawn(move || {
|
||||||
|
let val = String::from("hi");
|
||||||
|
tx.send(val).unwrap();
|
||||||
|
// Can't use after `send` call because the receiving
|
||||||
|
// thread may modify the value.
|
||||||
|
// println!("val is {val}");
|
||||||
|
});
|
||||||
|
|
||||||
|
// receiver has two useful methods: `recv` and `try_recv`.
|
||||||
|
// `recv` will block main thread's execution.
|
||||||
|
// `try_recv` useful if this thread has other work to do
|
||||||
|
// while waiting for messages.
|
||||||
|
let received = rx.recv().unwrap();
|
||||||
|
println!("Got: {received}");
|
||||||
|
|
||||||
|
// Sending multiple values and seeing the reciever waiting
|
||||||
|
|
||||||
|
println!("Sending multiple values and seeing the receiver waiting section");
|
||||||
|
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
let vals = vec![
|
||||||
|
String::from("hi"),
|
||||||
|
String::from("from"),
|
||||||
|
String::from("the"),
|
||||||
|
String::from("thread"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for val in vals {
|
||||||
|
tx.send(val).unwrap();
|
||||||
|
thread::sleep(Duration::from_secs(1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for received in rx {
|
||||||
|
println!("Got: {received}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creating multiple producers by cloning the transmitter
|
||||||
|
|
||||||
|
println!("Creating multiple producers by cloning the transmitter");
|
||||||
|
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
let tx1 = tx.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
let vals = vec![
|
||||||
|
String::from("hi"),
|
||||||
|
String::from("from"),
|
||||||
|
String::from("the"),
|
||||||
|
String::from("thread"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for val in vals {
|
||||||
|
tx1.send(val).unwrap();
|
||||||
|
thread::sleep(Duration::from_secs(1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
let vals = vec![
|
||||||
|
String::from("more"),
|
||||||
|
String::from("messages"),
|
||||||
|
String::from("for"),
|
||||||
|
String::from("you"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for val in vals {
|
||||||
|
tx.send(val).unwrap();
|
||||||
|
thread::sleep(Duration::from_secs(1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for received in rx {
|
||||||
|
println!("Got: {received}");
|
||||||
|
}
|
||||||
|
}
|
7
ch16/shared-state/Cargo.lock
generated
Normal file
7
ch16/shared-state/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shared-state"
|
||||||
|
version = "0.1.0"
|
6
ch16/shared-state/Cargo.toml
Normal file
6
ch16/shared-state/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "shared-state"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
101
ch16/shared-state/src/main.rs
Normal file
101
ch16/shared-state/src/main.rs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
//! # Shared-State Concurrency
|
||||||
|
//!
|
||||||
|
//! This is another way to handle concurrency. Sharing data.
|
||||||
|
//! Consider the slogan: "do not communicate by sharing memory."
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Using mutexes to allow access to data from one thread at a time
|
||||||
|
//
|
||||||
|
// Mutex is an abbreviation for mutual exclusion. Allows only one
|
||||||
|
// thread to access some data at any given time.
|
||||||
|
// To access data in a mutex, thread must first signal it wants
|
||||||
|
// access by asking to acquire the mutex's lock. The lock is
|
||||||
|
// a data structure part of the mutex that keeps track of who
|
||||||
|
// currently has exclusive access to the data. Therefore,
|
||||||
|
// mutex described as guarding the data.
|
||||||
|
//
|
||||||
|
// Mutexes have two rules:
|
||||||
|
// 1) Must attempt to acquire the lock before using the data
|
||||||
|
// 2) When done with data that mutex guards, must unlock data
|
||||||
|
// so other threads can acquire lock.
|
||||||
|
|
||||||
|
let m = Mutex::new(5);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut num = m.lock().unwrap();
|
||||||
|
*num = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("m = {m:?}");
|
||||||
|
|
||||||
|
// Sharing a Mutex<T> Between multiple threads
|
||||||
|
|
||||||
|
// let counter = Mutex::new(0);
|
||||||
|
// let mut handles = vec![];
|
||||||
|
|
||||||
|
// for _ in 0..10 {
|
||||||
|
// let handle = thread::spawn(move || {
|
||||||
|
// let mut num = counter.lock().unwrap();
|
||||||
|
|
||||||
|
// *num += 1;
|
||||||
|
// });
|
||||||
|
// handles.push(handle);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for handle in handles {
|
||||||
|
// handle.join().unwrap();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// println!("Result: {}", *counter.lock().unwrap());
|
||||||
|
|
||||||
|
// Multiple ownership with multiple threads
|
||||||
|
|
||||||
|
// let counter = Rc::new(Mutex::new(0));
|
||||||
|
// let mut handles = vec![];
|
||||||
|
|
||||||
|
// for _ in 0..10 {
|
||||||
|
// let counter = Rc::clone(&counter);
|
||||||
|
// let handle = thread::spawn(move || {
|
||||||
|
// let mut num = counter.lock().unwrap();
|
||||||
|
|
||||||
|
// *num += 1;
|
||||||
|
// });
|
||||||
|
// handles.push(handle);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for handle in handles {
|
||||||
|
// handle.join().unwrap();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// println!("Result: {}", *counter.lock().unwrap());
|
||||||
|
|
||||||
|
// Atomic reference counting with Arc<T>
|
||||||
|
//
|
||||||
|
// Arc<T> is like Rc<T> is safe to use concurrent situations.
|
||||||
|
// The a stands for atomic meanings it's an atomically reference
|
||||||
|
// counted type. Thread safety like this comes at an example.
|
||||||
|
// Arc<T> and Rc<T> have the same API.
|
||||||
|
|
||||||
|
let counter = Arc::new(Mutex::new(0));
|
||||||
|
let mut handles = vec![];
|
||||||
|
|
||||||
|
for _ in 0..10 {
|
||||||
|
let counter = Arc::clone(&counter);
|
||||||
|
let handle = thread::spawn(move || {
|
||||||
|
let mut num = counter.lock().unwrap();
|
||||||
|
|
||||||
|
*num += 1;
|
||||||
|
});
|
||||||
|
handles.push(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
for handle in handles {
|
||||||
|
handle.join().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Result: {}", *counter.lock().unwrap());
|
||||||
|
}
|
7
ch16/threads/Cargo.lock
generated
Normal file
7
ch16/threads/Cargo.lock
generated
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "threads"
|
||||||
|
version = "0.1.0"
|
6
ch16/threads/Cargo.toml
Normal file
6
ch16/threads/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "threads"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
38
ch16/threads/src/main.rs
Normal file
38
ch16/threads/src/main.rs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Waiting for all threads to finish using join handles
|
||||||
|
// Without the join below, threads stop prematurely
|
||||||
|
// because there is no guarantee on the order in which
|
||||||
|
// threads run, also can't guarantee spawned thread
|
||||||
|
// will get to run at all.
|
||||||
|
|
||||||
|
// calling `join` on a handle blocks the thread currently
|
||||||
|
// running until the thread represented by `handle`
|
||||||
|
// terminates.
|
||||||
|
handle.join().unwrap();
|
||||||
|
|
||||||
|
// Using move closures with threads
|
||||||
|
//
|
||||||
|
// Often use move keyword with closures because
|
||||||
|
// closure takes ownership fo values it uses from environment.
|
||||||
|
|
||||||
|
let v = vec![1, 2, 3];
|
||||||
|
let handle = thread::spawn(move || {
|
||||||
|
println!("Here's a vector: {v:?}");
|
||||||
|
});
|
||||||
|
handle.join().unwrap();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user