Rust'ta iş parçacıklarıyla çalışan güvenlik, iki otomatik trait aracılığıyla sağlanır: Send ve Sync.
Send bir türü iş parçacıkları arasında (sahipliği aktararak) iletmeye izin verir.Sync bir türün birden fazla iş parçacığı tarafından aynı anda güvenli bir şekilde kullanılabileceğini garanti eder (referanslar aracılığıyla).Rust'taki çoğu standart tür, varsayılan olarak bu trait'leri uygular. Örneğin, Arc<T>, Mutex<T> — Send ve Sync (eğer T de bu trait'lere uyuyorsa).
Kendi türleriniz için bu trait'leri açıkça yasaklayabilir veya uygulayabilirsiniz. Örneğin, güvensiz bir iç alanınız varsa (örneğin, ham bir işaretçi veya dış kaynaklar), türleri !Send veya !Sync yapmalısınız:
use std::marker::PhantomData; use std::rc::Rc; struct MyType { not_thread_safe: Rc<u32>, _marker: PhantomData<*const ()>, } // Rc<u32> Send/Sync uygulamaz, bu yüzden MyType bu trait'leri de uygulamayacaktır.
Düşük seviyeli bir sarıcı uygulayıp iş parçacığı güvenliğini manuel olarak yönetirseniz, Send/Sync'i manuel olarak (unsafe) uygulayabilirsiniz:
unsafe impl Send for MyType {} unsafe impl Sync for MyType {}
Bu, programcının iş parçacığı güvenliğini garanti etme sorumluluğudur.
Arc<Rc<T>> ile Rc<T>'yi birden fazla iş parçacığına çıkarırsanız ne olur?
Çoğu kişi Arc'ın her şeyi koruduğunu düşünür. Ancak Rc<T> Send/Sync uygulamaz, Arc içinde sarmasında bile! İşte şöyle:
use std::rc::Rc; use std::sync::Arc; fn main() { let data = Arc::new(Rc::new(5)); // std::thread::spawn(move || { // println!("{:?}", data); // }); // Derleyici bunu yapmanıza izin vermez! }
Arc, iç kısımlardaki Send/Sync eksikliğini telafi etmez.
Hikaye
Projede Arc<Rc<T>> kullanılarak verilerin iş parçacıkları arasında paylaşılmasına ve kilitlenmeyen bir şekilde sahipliğin bölüşülmesine çalışıldı. Program, öngörülemeyen davranışlarla çalışma sırasında çöküyordu; meğerse Rc iş parçacığı güvenli değilmiş ve Send/Sync trait'leri hakkında yeterli bilgi eksikliği vardı.
Hikaye
Kendin yap bir olay döngüsü içinde State türü üzerinde ham bir işaretçi verileri tuttular. State türü unsafe impl Send olarak işaretlendi, ancak senkronizasyonu ayarlamayı unuttular. Sonuç olarak, sürümden sonra ortaya çıkan klasik bir veri yarışı meydana geldi.
Hikaye
Bir geliştirici Mutex üzerinde yeni bir tip sarıcı uyguladı, ancak yanlışlıkla !Sync yaptı ve Sync'i manuel olarak uygulamayı unuttu. Bu, türün çoklu iş parçacığı bağlamında (örneğin, Arc<Mutex<T>> içinde) kullanılmasını engelledi, çünkü derleyici Sync'i talep etti. unsafe impl Sync uygulanarak ve güvenlik analizi yapılarak düzeltildi.