深入淺出Rust(第四部分)


傳送門(mén):
深入淺出Rust(第一部分-1)
深入淺出Rust(第一部分-2)
深入淺出Rust(第二部分-1)
深入淺出Rust(第二部分-2)
深入淺出Rust(第三部分-1)
深入淺出Rust(第三部分-2)
深入淺出Rust(第四部分)
深入淺出Rust(第五部分)


第四部分 - 線程安全

Rust在編譯器層面做了很多工作,進(jìn)而在編譯過(guò)程就發(fā)現(xiàn)和阻止線程不安全的情形

第27章 線程安全

1. 什么是線程

2. 啟動(dòng)線程

thread::spawn(MOVE ||{
    //線程內(nèi)部邏輯
});

相當(dāng)于做了閉包代碼塊

Thead模塊常用API:

  • thread::sleep(dur: Duration)
  • thread::yield_now()
  • thread::current()
  • thread::park()
  • thread::Thread::unpark(&self)

3. 避免數(shù)據(jù)競(jìng)爭(zhēng)

直接傳mut變量,copy類(lèi)型進(jìn)去,都會(huì)造成編譯錯(cuò)誤.

4. send & Sync

Rust正是通過(guò)這兩個(gè)特殊的trait,對(duì)線程安全進(jìn)行了控制

pub fn spawn<F,T>(f: F) -> JoinHandle<T>
    where F: FnOne() -> T, F:Send + 'static, T: Send +'static

從spawn的函數(shù)簽名可以參數(shù),F和T需要滿足Send trait,因此在線程間傳遞所有權(quán)會(huì)發(fā)生安全問(wèn)題的類(lèi)型,Rust就能檢測(cè)出來(lái).

第28章 詳解Send和Sync

1. 什么是Send

  • Send trait滿足不同線程間傳遞所有權(quán)是安全的
  • 包括基本類(lèi)型,內(nèi)部不含引用的類(lèi)型(string),泛型參數(shù)滿足的(Cell<T>,RefCell<T>,Mutex<T>)
  • 不包括RC<T>

2. 什么是Sync

  • Sync trait滿足不同線程使用&T訪問(wèn)同一變量
  • 包括基本類(lèi)型,泛型參數(shù)滿足的(Box<T>,Vec<T>,Mutex<T>)
  • 不包括Cell<T>,RefCell<T>

3. 自動(dòng)推理

  • 實(shí)際上 Send和Sync都是std::marker模塊的特殊trait,用戶不用手寫(xiě)impl,而是編譯器自動(dòng)完成
  • 如果要自己寫(xiě),一定要配合unsafe關(guān)鍵字,并且自己保證其安全性

第29章 狀態(tài)共享

1. ARC

  • Arc是Rc的線程安全版本
29-1.png

2. Mutex(重點(diǎn))

  • Mutex提供安全的內(nèi)部可變性(通過(guò)lock()調(diào)用)
  • lock()方法返回LockResult類(lèi)型,
type LockResult<Guard> = Result<Guard, PoisonError<Guard>>;

如果lock過(guò)程發(fā)生了panic,那么這個(gè)Mutex則變?yōu)?有毒"狀態(tài).

3. RwLock

  • RwLock和使用類(lèi)似Mutex,相對(duì)來(lái)說(shuō),更不嚴(yán)格一點(diǎn),可以通過(guò)read實(shí)現(xiàn)共享,write實(shí)現(xiàn)獨(dú)占.

4. Atomic

  • Atomic系列類(lèi)型提供了"原子操作",因此他們都是符合Sync的,可以在多線程間共享使用.
  • 修改時(shí)要用fetch_add()和fetch_sub()實(shí)現(xiàn)原子化的數(shù)據(jù)增減,而load,store本身雖然原子化,但是無(wú)法保證兩個(gè)操作之間的原子化.

5. 死鎖

  • rust并不保證線程間不出現(xiàn)死鎖,這個(gè)需要程序員自行完善邏輯

6. Barrier

  • Barrier類(lèi)似waitgroup,當(dāng)條件完全滿足才能繼續(xù)

7. Condvar(重點(diǎn))

  • Condvar通常與Mutex配套使用,用來(lái)在線程之前進(jìn)行消息傳遞,從而進(jìn)行手工同步
29-2.png

8. 全局變量

  • 全局變量顯然不適合用在多線程里,太容易造成線程不安全了.
  • mut全局變量基本無(wú)法滿足Send,Sync約束
  • 可以用atomic型全局變量(限定為簡(jiǎn)單的i32)

9. 線程局部存儲(chǔ)

  • threalocal!{}宏聲明,××.with{}限定使用范圍.
  • java也一樣這么搞的

第30章 管道

顯然,Rust的channel比起Go,還是有差距的.

1. 異步管道

  • 異步管道(std::sync::mpsc::channel),實(shí)現(xiàn)管道的異步讀寫(xiě)(不需要考慮管道本身大小)
  • Send和Receiver都必須滿足T: Send約束.
  • 可以實(shí)現(xiàn)多發(fā)單收

2. 同步管道

  • 異步管道(std::sync::mpsc::sync_channel),實(shí)現(xiàn)管道的同步讀寫(xiě)(管道大小為1)

第31章 第三方并行開(kāi)發(fā)庫(kù)

1. threadpool

  • new出大小,execute執(zhí)行

2. scoped-threadpool

  • 線程內(nèi)部直接使用&mut訪問(wèn)父線程變量,而不需用Arc包裝

3. parking_lot

  • 實(shí)現(xiàn)另外一套同步原語(yǔ)(Mutex,CondVar)

4. crossbeam

  • 實(shí)現(xiàn)了雙端管道

5. rayon

31-1.png
  • 實(shí)現(xiàn)了并行迭代器和join()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容