ข้ามไปยังเนื้อหา

Send และ Sync

JavaScript หลีกเลี่ยงปัญหา thread-safety โดยสิ้นเชิง — มีแค่ thread เดียว (ต่อ Worker) ดังนั้นคำถามที่ว่า “สอง thread สามารถเข้าถึงค่านี้พร้อมกันได้ไหม?” จึงไม่เกิดขึ้นเลย ไม่มีแนวคิด thread safety ระดับ type ใน TypeScript

Rust รองรับ parallelism จริง แปลว่าสอง thread เข้าถึง memory ก้อนเดียวกันพร้อมกันได้จริง ๆ เพื่อให้ปลอดภัยโดยไม่ต้องพึ่ง garbage collector หรือ lock ตอน runtime ทาง Rust เลยใช้ marker trait สองตัว: Send และ Sync

Traitความหมายตัวอย่าง type
Sendค่าของ type T สามารถ ย้าย ไปยัง thread อื่นได้i32, String, Vec<T>, Arc<T>
Syncshared reference &T สามารถส่งไปยัง thread อื่นได้i32, Arc<T>, Mutex<T>
ไม่ใช่ Sendไม่สามารถย้ายไปยัง thread อื่นได้Rc<T> (non-atomic reference count)
ไม่ใช่ Syncไม่สามารถแชร์ reference ข้าม threads ได้Cell<T>, RefCell<T>

trait สองตัวนี้ compiler implement ให้อัตโนมัติ โดยดูจาก type ที่อยู่ภายใน struct ของคุณ แทบไม่มีเคสที่ต้อง implement เอง และกฎจะ propagate ต่อ: ถ้า struct มี field ตัวใดไม่ใช่ Send ตัว struct เองก็ไม่ใช่ Send ด้วย

TypeScript
// TypeScript ไม่มี type สำหรับ thread-safety
// ภาษารับประกันความปลอดภัยโดยมีแค่ thread เดียวต่อ Worker
// ไม่มีแนวคิด Send หรือ Sync ระดับ type
// ใน Worker คุณสื่อสารได้เฉพาะผ่าน structured-clone (postMessage):
// plain objects, arrays, ArrayBuffer ฯลฯ
// ไม่สามารถส่ง class instance ที่มี methods, closure, หรือ WeakRef ได้
const worker = new Worker('./worker.js');
// นี่ ทำงานได้: number เป็น structured-cloneable
worker.postMessage(42);
// นี่จะ FAIL ณ runtime: functions ไม่สามารถ clone ได้
// worker.postMessage(() => 42); // DataCloneError
Rust
// Rust: Send/Sync เป็นการรับประกัน ณ compile time ไม่ใช่ runtime checks
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
// Arc<Mutex<T>> ทั้ง Send และ Sync:
// - Arc: thread-safe reference counting (vs Rc ที่ไม่ใช่ Send)
// - Mutex: ให้ interior mutability พร้อม lock
let shared: Arc<Mutex<Vec<u32>>> = Arc::new(Mutex::new(vec![]));
let mut handles = vec![];
for i in 0..4 {
let data = Arc::clone(&shared); // clone ราคาถูก — แค่ increment pointer
let h = thread::spawn(move || {
data.lock().unwrap().push(i); // lock, push, auto-unlock
});
handles.push(h);
}
for h in handles { h.join().unwrap(); }
let mut result = shared.lock().unwrap().clone();
result.sort();
println!("collected: {:?}", result); // collected: [0, 1, 2, 3]
}
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let data: Arc<Mutex<Vec<u32>>> = Arc::new(Mutex::new(vec![]));
let mut handles = vec![];
for i in 0..4 {
let d = Arc::clone(&data);
let h = thread::spawn(move || {
d.lock().unwrap().push(i);
});
handles.push(h);
}
for h in handles {
h.join().unwrap();
}
let mut result = data.lock().unwrap().clone();
result.sort();
println!("collected: {:?}", result);
}
Marker trait `Send` ใน Rust หมายความว่าอะไร?
ทำไม `Rc<T>` ถึงไม่ใช่ `Send` แต่ `Arc<T>` ใช่?
การละเมิด Send/Sync ถูกตรวจพบเมื่อไหร่ใน Rust?