Send 和 Sync

std::marker 模塊中,有兩個 trait:SendSync,它們與多線程安全相關。

標記為 marker trait 的 trait,它實際就是一種約定,沒有方法的定義,也沒有關聯元素(associated items)。僅僅是一種約定,實現了它的類型必須滿足這種約定。一種類型是否加上這種約定,要麼是編譯器的行為,要麼是人工手動的行為。

SendSync 在大部分情況下(針對 Rust 的基礎類型和 std 中的大部分類型),會由編譯器自動推導出來。對於不能由編譯器自動推導出來的類型,要使它們具有 SendSync 的約定,可以由人手動實現。實現的時候,必須使用 unsafe 前綴,因為 Rust 默認不信任程序員,由程序員自己控制的東西,統統標記為 unsafe,出了問題(比如,把不是線程安全的對象加上 Sync 約定)由程序員自行負責。

它們的定義如下:

如果 T: Send,那麼將 T 傳到另一個線程中時(按值傳送),不會導致數據競爭或其它不安全情況。

  1. Send 是對象可以安全發送到另一個執行體中;
  2. Send 使被髮送對象可以和產生它的線程解耦,防止原線程將此資源釋放後,在目標線程中使用出錯(use after free)。

如果 T: Sync,那麼將 &T 傳到另一個線程中時,不會導致數據競爭或其它不安全情況。

  1. Sync 是可以被同時多個執行體訪問而不出錯;
  2. Sync 防止的是競爭;

推論:

  1. T: Sync 意味著 &T: Send
  2. Sync + Copy = Send
  3. T: Send 時,可推導出 &mut T: Send
  4. T: Sync 時,可推導出 &mut T: Sync
  5. &mut T: Send 時,不能推導出 T: Send

(注:T, &T, &mut TBox<T> 等都是不同的類型)

具體的類型:

  1. 原始類型(比如: u8, f64),都是 Sync,都是 Copy,因此都是 Send
  2. 只包含原始類型的複合類型,都是 Sync,都是 Copy,因此都是 Send
  3. T: SyncBox<T>, Vec<T> 等集合類型是 Sync
  4. 具有內部可變性的的指針,不是 Sync 的,比如 Cell, RefCell, UnsafeCell
  5. Rc 不是 Sync。因為只要一做 &Rc<T> 操作,就會克隆一個新引用,它會以非原子性的方式修改引用計數,所以是不安全的;
  6. MutexRWLock 鎖住的類型 T: Send,是 Sync 的;
  7. 原始指針(*mut, *const)既不是 Send 也不是 Sync

Rust 正是通過這兩大武器:所有權和生命週期 + Send 和 Sync(本質上為類型系統)來為併發編程提供了安全可靠的基礎設施。使得程序員可以放心在其上構建穩健的併發模型。這也正是 Rust 的核心設計觀的體現:內核只提供最基礎的原語,真正的實現能分離出去就分離出去。併發也是如此。

results matching ""

    No results matching ""