Güvenli çoklu iş parçacığı ortamlarında çalışma sorunu programcılar tarafından uzun zamandır karşılaşılmakta ve yarış koşulları, tutarsız veriler ve bellek sızıntıları gibi sorunlarla sürekli olarak karşı karşıya kalınmaktadır. Rust, bu sorunları derleme aşamasında en aza indirmek için Send ve Sync marker-trait’leri ile benzersiz bir yaklaşım gerçekleştirmiştir.
Sorun — iş parçacıkları arasında paylaşılan verilere erişimin kontrol edilmemesi, bu da zor tespit edilebilen hatalara yol açmaktadır. Birçok dilde bu sorumluluk tamamen programcıya aittir, ancak Rust'da derleyici, iş parçacıkları arasında neyin aktarılabileceğini/paylaşılabileceğini kendisi kontrol eder.
Çözüm: Send trait'i, bir nesnenin bir iş parçacığından diğerine güvenli bir şekilde aktarılabilir olduğunu garanti eder. Sync ise bir nesneye farklı iş parçacıklarından referans ile ortak erişim imkanı sağlar. Rust'taki hemen hemen tüm standart türler otomatik olarak bu trait'leri uygular ve özel türler bunları manuel olarak uygulayabilir veya belirli durumlar için impl !Send veya impl !Sync şeklinde yasaklayabilir.
Kod örneği:
use std::sync::{Arc, Mutex}; use std::thread; 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(); } // counter her zaman 10 olacak, hafıza yarışları olmadan!
Anahtar özellikler:
Ham işaretçileri içeren bir tür Send veya Sync olabilir mi?
Hayır, eğer tür bir raw pointer ya da iş parçacığı güvenliği garantisi olmayan kaynaklar içeriyorsa, bu trait'leri uygulamaz veya geliştiricinin bunları manuel olarak uygulaması gerekir (genellikle unsafe impl Send/Sync ile).
Rc<T> ve RefCell<T> Send veya Sync midir?
Hayır, Rc<T> ve RefCell<T> çoklu iş parçacıkları için güvenli değildir (ne Send, ne de Sync). Çoklu iş parçacığı senaryoları için Arc<T> ve Mutex/RwLock kullanılır.
Eğer bir static değişken Sync’i uygulanmamış bir tür içeriyorsa ne olur?
Rust, böyle bir static değişkenin var olmasına izin vermez: bu değişkenin Sync olması gerekir, aksi takdirde derleyici bir hata verecektir.
Genç bir geliştirici, thread::spawn içinde bir Rc nesnesi koyar - kod, Rc nesnesinin iş parçacıkları arasında aktarılmadığı sürece derlenir. Eğer Rc'yi thread::spawn'dan çıkarmaya çalışırsa, Rc Send’i uygulamadığı için bir derleme hatası alır ve yarış koşullarından korunmaz.
Artılar:
Eksiler:
Çoklu iş parçacığı sayacı için Arc+Mutex kullanılır, tüm iş parçacıkları güvenli bir arabirim aracılığıyla aynı verilerle çalışır. Yarış koşulları yoktur, kod güvenli ve dayanıklıdır.
Artılar:
Eksiler: