Rust 中 Send 與 Sync 有什麼區別
Send
與 Sync
是兩個十分相近的 trait,它們是一起保證了 Rust 的線程安全,它們又有什麼異同點呢?
(Quick Question and Answer 系列旨在對小問題做簡短解答)
-
Send
表示數據能安全地被move
到另一個線程 -
Sync
表示數據能在多個線程中被同時安全地訪問
這裏 “安全” 指不會發生數據的競爭 (race condition)。
Send 代表沒有數據共享
數據如果被 move 到另一個線程裏,它還安全嗎?能正常使用嗎?如果可以,則說它是 Send
。
反例:Rc[1]。我們知道 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[2]。它滿足 Send
,但不滿足 Sync
。RefCell
不會與本線程的其它引用共享數據,所以被 move 到其它線程是安全的。但如果有多個線程同時擁有 RefCell 的引用,並同時獲取它的可變引用 (mutable reference) 並嘗試修改它,則會產生競爭,亦即沒有滿足原子性。
marker trait
最後要說的是,Send
和 Sync
都屬於 marker trait[3],marker trait 的特點是不包含任何方法,所以爲某個數據結構實現 marker trait 相當於人爲告訴編譯器,我實現的數據結構符合你的要求(如滿足 Send
, Sync
),編譯期間就放心吧。換句話說,編譯器並無法檢查你的實現到底是不是滿足 Send
或 Sync
,只能選擇相信程序員的聲明,如果程序員的實現有問題,只能程序員自己背鍋了。
原文鏈接:https://lotabout.me/2018/QQA-send-vs-sync-in-rust/
參考資料
[1]
Rc: https://doc.rust-lang.org/std/rc/struct.Rc.html
[2]
RefCell: https://doc.rust-lang.org/std/cell/struct.RefCell.html
[3]
marker trait: https://doc.rust-lang.org/std/marker/index.html
[4]
線程安全: https://zhuanlan.zhihu.com/p/24142191
[5]
Shared State Concurrency: https://doc.rust-lang.org/book/second-edition/ch16-03-shared-state.html
[6]
How Rust Achieves Thread Safety: https://manishearth.github.io/blog/2015/05/30/how-rust-achieves-thread-safety/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/K_Nj9ppttRoV96bp04prUA