Sorunun Tarihi:
Çok iş parçacıklı çalışma, birçok programlama dilinde hataların kaynağıdır: veri yarışı, kaynaklar için rekabet, anlaşılması zor hatalar. C++ ve Java'nın deneyimlerini inceleyen Rust'ın yaratıcıları, çoğu hatanın derleme aşamasında tespit edilmesini sağlamak için thread güvenliği mekanizmalarını doğrudan tip sistemine entegre etmeye karar verdiler.
Sorun:
Klasik dillerde genellikle programcının disiplinine ve dış araçlara güvenmek gerekir: veri mülkiyetinin aktarılması, paylaşılan değiştirilebilir bellek ve eş zamanlı erişim eksikliği kritik hatalara yol açabilir. Derleme aşamasında bellek yarışlarını önleyen bir sistem sağlamak gerekti.
Çözüm:
Rust'ta iş parçacıkları arasında veri senkronizasyonu ve aktarımı için standart kütüphaneden özel türler kullanılır — örneğin, Arc, Mutex ve kanallar. Send ve Sync trait'leri, derleyici tarafından otomatik olarak kontrol edilen anahtar rol oynamaktadır. Bir tip thread-safe (iş parçacığı güvenli) olarak kabul edilir, eğer:
Sync)Send uygulandığında iş parçacıkları arasında aktarılabilirKod örneği:
use std::sync::{Arc, Mutex}; use std::thread; fn main() { 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!("Sonuç: {}", *counter.lock().unwrap()); }
Anahtar Özellikler:
Mutex, RwLock, kanallar — sözleşmeye göre thread-safe'dirArc ve Mutex gibi sarmalayıcı türlerle gerçekleştirilirVeri iletimi için Rc<T> neden kullanılamaz?
Rc<T> Send trait'ini uygulamaz ve thread-safe değildir — içsel uygulaması, birden fazla iş parçacığı tarafından erişildiğinde veri yarışına yol açan kilitsiz referans sayacı üzerine kuruludur. İş parçacıkları için Arc<T> kullanın.
Kendi türüm için Send veya Sync'i manuel olarak uygulamak, derleyicinin kısıtlamalarını aşmamı sağlar mı?
Evet, ancak bu son derece tehlikelidir! İnvariyantları ihlal ederseniz (örneğin, çıplak bir işaretçi paylaşmak), veri yarışına yol açabilirsiniz. Manuel uygulamayı yalnızca thread güvenliği konusunda tamamen emin olan uzmanlar için bırakın.
Mutex Rust'ta ne zaman deadlock'a yol açabilir ve bu nasıl önlenir?
Deadlock, birden fazla mutex'in edinim sırası kararsızsa veya kilit bir iş parçacığında yinelemeli olarak kilitlenirse mümkündür (Mutex 'reentrant' değildir!).
use std::sync::Mutex; let a = Mutex::new(0); let _g1 = a.lock().unwrap(); let _g2 = a.lock().unwrap(); // panic: deadlock!
Bir geliştirici, bir web sunucusunda iş parçacıkları arasında durum iletimi için Rc<RefCell<T>> kullandı. Yerel testlerde çalıştı, ancak üretimde veri yarışları oluştu: bazen değişkenler "durumlarını kaybetti", bazen sunucu çöktü.
Artılar:
Eksiler:
Durumu iletmek için Arc<Mutex<T>> kullanımı, Send/Sync'ye katı bir uyum, iş yükünün kanallar aracılığıyla iş parçacıkları arasında dağıtılması, paylaşılan veri üzerinde hiçbir mut değişkeni kullanılmaması.
Artılar:
Eksiler: