std::marker
模塊中,有兩個(gè) trait:Send
和 Sync
,它們與多線程安全相關(guān)。
標(biāo)記為 marker trait
的 trait,它實(shí)際就是一種約定,沒有方法的定義,也沒有關(guān)聯(lián)元素(associated items)。僅僅是一種約定,實(shí)現(xiàn)了它的類型必須滿足這種約定。一種類型是否加上這種約定,要么是編譯器的行為,要么是人工手動(dòng)的行為。
Send
和 Sync
在大部分情況下(針對(duì) Rust 的基礎(chǔ)類型和 std 中的大部分類型),會(huì)由編譯器自動(dòng)推導(dǎo)出來。對(duì)于不能由編譯器自動(dòng)推導(dǎo)出來的類型,要使它們具有 Send
或 Sync
的約定,可以由人手動(dòng)實(shí)現(xiàn)。實(shí)現(xiàn)的時(shí)候,必須使用 unsafe
前綴,因?yàn)?Rust 默認(rèn)不信任程序員,由程序員自己控制的東西,統(tǒng)統(tǒng)標(biāo)記為 unsafe
,出了問題(比如,把不是線程安全的對(duì)象加上 Sync
約定)由程序員自行負(fù)責(zé)。
它們的定義如下:
如果 T: Send
,那么將 T
傳到另一個(gè)線程中時(shí)(按值傳送),不會(huì)導(dǎo)致數(shù)據(jù)競(jìng)爭(zhēng)或其它不安全情況。
Send
是對(duì)象可以安全發(fā)送到另一個(gè)執(zhí)行體中;Send
使被發(fā)送對(duì)象可以和產(chǎn)生它的線程解耦,防止原線程將此資源釋放后,在目標(biāo)線程中使用出錯(cuò)(use after free)。如果 T: Sync
,那么將 &T
傳到另一個(gè)線程中時(shí),不會(huì)導(dǎo)致數(shù)據(jù)競(jìng)爭(zhēng)或其它不安全情況。
Sync
是可以被同時(shí)多個(gè)執(zhí)行體訪問而不出錯(cuò);Sync
防止的是競(jìng)爭(zhēng);推論:
T: Sync
意味著 &T: Send
;Sync + Copy = Send
;T: Send
時(shí),可推導(dǎo)出 &mut T: Send
;T: Sync
時(shí),可推導(dǎo)出 &mut T: Sync
;&mut T: Send
時(shí),不能推導(dǎo)出 T: Send
;(注:T
, &T
, &mut T
,Box<T>
等都是不同的類型)
具體的類型:
Sync
,都是 Copy
,因此都是 Send
;Sync
,都是 Copy
,因此都是 Send
;T: Sync
,Box<T>
, Vec<T>
等集合類型是 Sync
;Sync
的,比如 Cell
, RefCell
, UnsafeCell
;Rc
不是 Sync
。因?yàn)橹灰蛔?&Rc<T>
操作,就會(huì)克隆一個(gè)新引用,它會(huì)以非原子性的方式修改引用計(jì)數(shù),所以是不安全的;Mutex
和 RWLock
鎖住的類型 T: Send
,是 Sync
的;*mut
, *const
)既不是 Send
也不是 Sync
;Rust 正是通過這兩大武器:所有權(quán)和生命周期
+ Send 和 Sync
(本質(zhì)上為類型系統(tǒng))來為并發(fā)編程提供了安全可靠的基礎(chǔ)設(shè)施。使得程序員可以放心在其上構(gòu)建穩(wěn)健的并發(fā)模型。這也正是 Rust 的核心設(shè)計(jì)觀的體現(xiàn):內(nèi)核只提供最基礎(chǔ)的原語,真正的實(shí)現(xiàn)能分離出去就分離出去。并發(fā)也是如此。