ProgramlamaSistem kütüphaneleri geliştiricisi / Backend geliştirici

Rust'ta 'çoklu iş parçacığı güvenliği' (Send ve Sync) nasıl çalışır ve kullanıcı tanımlı türler için nasıl uygulanabilir/kısıtlanabilir?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap.

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.

Kandırmaca soru.

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.

Konunun inceliklerini bilmemekten kaynaklanan gerçek hata örnekleri.


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.