QQA: Rust 中 Send 與 Sync 有什麼區別
Send
與 Sync
是兩個十分相近的 trait,它們是一起保證了 Rust 的執行緒安全,它們又有什麼異同點呢?
(Quick Question and Answer 系列旨在對小問題做簡短解答)
Send
表示資料能安全地被move
到另一個執行緒Sync
表示資料能在多個執行緒中被同時安全地訪問
這裡“安全”指不會發生資料的競爭 (race condition)。
#Send 代表沒有資料共享
資料如果被 move 到另一個執行緒裡,它還安全嗎?能正常使用嗎?如果可以,則說它是
Send
。
反例: Rc。我們知道 Rc
中儲存了一個 reference count,記錄有多少變數引用了當前的資料,當 reference count
歸 0 時才釋放(drop)資料本身。現在如果我們把一個 Rc
Rc
的實現還是決定了不同執行緒裡的 Rc
會指向同一個 reference count,這意味著不同的執行緒可能同時修改 reference count,而 Rc
內部並沒有實現同步機制,因此是不安全的。
這裡有一個推論:一個結構(Struct)如果不滿足 Send
,是不是意味著它的某個內部資料不滿足Sync
呢?參考 Rc
的例子,就是內部的 reference count 不滿足 Sync 。只是目前沒有找到相關的證明。
#Sync 代表同步
如果多個執行緒同時訪問某個資料,會不會產生競爭?如果還是安全的,我們就能說它是
Sync
。
反例:Send
,但不滿足 Sync
。 RefCell
不會與本執行緒的其它引用共享資料,所以被
move 到其它執行緒是安全的。但如果有多個執行緒同時擁有 RefCell 的引用,並同時獲取它的可變引用(mutable reference)並嘗試修改它,則會產生競爭,亦即沒有滿足原子性。
#marker trait
最後要說的是,Send
和 Sync
都屬於 marker
trait,marker trait 的特點是不包含任何方法,所以為某個資料結構實現 marker trait 相當於人為告訴編譯器,我實現的資料結構符合你的要求(如滿足 Send
, Sync
),編譯期間就放心吧。換句話說,編譯器並無法檢查你的實現到底是不是滿足 Send
Sync
,只能選擇相信程式設計師的宣告,如果程式設計師的實現有問題,只能程式設計師自己背鍋了。