Threads
การ Spawn Thread ด้วย std::thread
หัวข้อที่มีชื่อว่า “การ Spawn Thread ด้วย std::thread”standard library ของ Rust มี OS thread ผ่าน std::thread::spawn คุณส่ง closure และฟังก์ชันจะส่งคืน JoinHandle<T> — handle ที่คุณใช้รอให้ thread เสร็จสิ้นและดึงค่าที่ส่งคืน
use std::thread;
fn main() { let handle = thread::spawn(|| { // นี่รันบน OS thread ใหม่ 42 });
let result = handle.join().unwrap(); // บล็อกจนกว่า thread จะเสร็จ println!("Thread returned: {}", result);}closure จะเป็น move || { ... } เมื่อต้องการ capture ตัวแปรจาก scope ที่ครอบอยู่ — ไม่เช่นนั้นคอมไพเลอร์ไม่สามารถรับประกันได้ว่าข้อมูลที่ถูก capture จะมีอายุยาวพอ
การย้ายข้อมูลเข้า Thread
หัวข้อที่มีชื่อว่า “การย้ายข้อมูลเข้า Thread”เนื่องจาก thread อาจมีอายุยาวกว่า scope ที่ถูก spawn ข้อมูลใดก็ตามที่ thread capture จะต้องเป็นเจ้าของโดย thread คำสั่ง move ย้าย ownership ของตัวแปรที่ถูก capture เข้าสู่ closure
use std::thread;
fn main() { let message = String::from("hello from the main thread");
let handle = thread::spawn(move || { // message ถูกย้ายมาที่นี่ — thread เป็นเจ้าของตัวเองแล้ว println!("{}", message); });
handle.join().unwrap(); // println!("{}", message); // จะไม่คอมไพล์ — ถูกย้ายไปแล้ว}การแชร์ State ด้วย Arc<Mutex<T>>
หัวข้อที่มีชื่อว่า “การแชร์ State ด้วย Arc<Mutex<T>>”เพื่อแชร์ข้อมูลที่ mutable ระหว่างหลาย thread ให้ห่อข้อมูลด้วย Arc<Mutex<T>>:
Mutex<T>ให้ mutual exclusion — มีแค่ thread เดียวที่สามารถล็อคได้ในแต่ละครั้งArc<T>(Atomically Reference Counted) ให้หลาย thread ถือ pointer ที่นับ reference ไปยัง allocation เดียวกัน
คุณ clone Arc ก่อนย้าย clone นั้นเข้าไปในแต่ละ thread Mutex ที่อยู่ข้างในถูกแชร์ ไม่ใช่ clone
use std::thread;use std::sync::{Arc, Mutex};
fn main() { let counter = Arc::new(Mutex::new(0_i32)); let mut handles = Vec::new();
for _ in 0..4 { let counter = Arc::clone(&counter); // เพิ่ม ref-count ราคาถูก let h = thread::spawn(move || { let mut n = counter.lock().unwrap(); // ขอ lock *n += 1; }); // lock ถูก release เมื่อ n drop handles.push(h); }
for h in handles { h.join().unwrap(); }
println!("Final count: {}", *counter.lock().unwrap());}การรวบรวมผลลัพธ์จากหลาย Thread
หัวข้อที่มีชื่อว่า “การรวบรวมผลลัพธ์จากหลาย Thread”รูปแบบที่พบบ่อยคือให้แต่ละ thread คำนวณค่าและ push เข้าไปใน Vec ที่แชร์กัน หลังจาก thread ทั้งหมดเสร็จสิ้น เรา sort ผลลัพธ์เพื่อให้ output เป็น deterministic ไม่ว่า scheduling order จะเป็นอย่างไร
use std::thread;use std::sync::{Arc, Mutex};
fn main() { let results = Arc::new(Mutex::new(Vec::new())); let mut handles = Vec::new();
for i in 0..5 { let results = Arc::clone(&results); let handle = thread::spawn(move || { let square = i * i; let mut v = results.lock().unwrap(); v.push(square); }); handles.push(handle); }
for h in handles { h.join().unwrap(); }
let mut final_results = results.lock().unwrap().clone(); final_results.sort(); println!("Squares: {:?}", final_results); let sum: i32 = final_results.iter().sum(); println!("Sum: {}", sum);}Compiling…