Rust 中 Send 與 Sync 有什麼區別

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

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

這裏 “安全” 指不會發生數據的競爭 (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,但不滿足 SyncRefCell 不會與本線程的其它引用共享數據,所以被 move 到其它線程是安全的。但如果有多個線程同時擁有 RefCell 的引用,並同時獲取它的可變引用 (mutable reference) 並嘗試修改它,則會產生競爭,亦即沒有滿足原子性。

marker trait

最後要說的是,SendSync 都屬於 marker trait[3],marker trait 的特點是不包含任何方法,所以爲某個數據結構實現 marker trait 相當於人爲告訴編譯器,我實現的數據結構符合你的要求(如滿足 Send, Sync),編譯期間就放心吧。換句話說,編譯器並無法檢查你的實現到底是不是滿足 SendSync,只能選擇相信程序員的聲明,如果程序員的實現有問題,只能程序員自己背鍋了。

原文鏈接: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