1. 程式人生 > >QQA: Rust 中 Send 與 Sync 有什麼區別

QQA: Rust 中 Send 與 Sync 有什麼區別

SendSync 是兩個十分相近的 trait,它們是一起保證了 Rust 的執行緒安全,它們又有什麼異同點呢?

(Quick Question and Answer 系列旨在對小問題做簡短解答)

  • Send 表示資料能安全地被 move 到另一個執行緒
  • Sync 表示資料能在多個執行緒中被同時安全地訪問

這裡“安全”指不會發生資料的競爭 (race condition)。

#Send 代表沒有資料共享

資料如果被 move 到另一個執行緒裡,它還安全嗎?能正常使用嗎?如果可以,則說它是 Send

反例: Rc。我們知道 Rc 中儲存了一個 reference count,記錄有多少變數引用了當前的資料,當 reference count 歸 0 時才釋放(drop)資料本身。現在如果我們把一個 Rc

move 到另一個執行緒裡,儘管是 move,Rc 的實現還是決定了不同執行緒裡的 Rc 會指向同一個 reference count,這意味著不同的執行緒可能同時修改 reference count,而 Rc 內部並沒有實現同步機制,因此是不安全的。

這裡有一個推論:一個結構(Struct)如果不滿足 Send,是不是意味著它的某個內部資料不滿足Sync 呢?參考 Rc 的例子,就是內部的 reference count 不滿足 Sync 。只是目前沒有找到相關的證明。

#Sync 代表同步

如果多個執行緒同時訪問某個資料,會不會產生競爭?如果還是安全的,我們就能說它是 Sync

反例:

RefCell。它滿足 Send,但不滿足 SyncRefCell 不會與本執行緒的其它引用共享資料,所以被 move 到其它執行緒是安全的。但如果有多個執行緒同時擁有 RefCell 的引用,並同時獲取它的可變引用(mutable reference)並嘗試修改它,則會產生競爭,亦即沒有滿足原子性。

#marker trait

最後要說的是,SendSync 都屬於 marker trait,marker trait 的特點是不包含任何方法,所以為某個資料結構實現 marker trait 相當於人為告訴編譯器,我實現的資料結構符合你的要求(如滿足 Send, Sync),編譯期間就放心吧。換句話說,編譯器並無法檢查你的實現到底是不是滿足 Send

Sync,只能選擇相信程式設計師的宣告,如果程式設計師的實現有問題,只能程式設計師自己背鍋了。

#參考