c++11併發程式設計歷程(15):併發設計以及併發設計資料結構的思考

_李白_發表於2020-11-26

目錄

1、併發設計的意義

2、併發設計資料結構的準則

2.1、資料結構執行緒安全的原理

2.2、實現真正的併發


1、併發設計的意義

  在最基本的層面,為併發設計資料結構意味著多個執行緒可以同時使用此資料結構,執行相同或不同的操作,並且每個執行緒都有資料結構的一致性試圖。

  不會丟失或破壞資料,維持所有不變數,並且沒有不確定的競爭條件,此種資料結構就被稱為執行緒安全的。通常,只有在特定的併發存取下,一種資料型別才是安全的。

  實際上,併發設計遠遠不只是為多個執行緒提供存取資料結構的併發機會。本質上,互斥元提供的是互斥,一次只允許一個執行緒獲取互斥元的鎖。一個互斥元通過明確阻止對它所保護資料進行併發存取來保護資料,這被稱為序列化,即多個執行緒輪流存取互斥元保護的資料,它們必須線性的而非併發地存取資料。

   核心思想是:更小的保護區域,更少的操作被序列化,以及更高的併發潛能。

2、併發設計資料結構的準則

為併發存取設計資料結構時,需要考慮兩方面:保證存取是安全的以及允許真正的併發存取

2.1、資料結構執行緒安全的原理

  • 保證當前資料結構不變性被別的執行緒破壞時的狀態不被別的任何執行緒看到(簡單理解就是一個執行緒寫的時候,其餘執行緒不能讀也不能寫)
  • 注意避免資料介面介面所固有的競爭現象,通過為完整操作提供函式,而不是提供步驟
  • 注意當出現例外時,資料結構是怎樣來保證不變性不被破壞的。
  • 當使用資料結構時,通過限制鎖的範圍和避免使用巢狀鎖,來降低產生死鎖的機會

在考慮這些細節前,先考慮使用資料結構時的限制條件也是很重要的,如果一個函式通過特殊函式使用資料結構,那麼其他執行緒呼叫哪個函式是安全的?

這是要考慮的關鍵性問題。大多數建構函式和解構函式需要以獨佔方式訪問資料結構,即需要使用者保證它們在建構函式完成前或者解構函式開始後沒有被使用。

2.2、實現真正的併發

這個問題比較複雜,我們可以從以下角度來切入

  • 鎖的範圍能否被限定,使得一個操作的一部分可以在鎖外被執行?
  • 資料結構的不同部分能否被不同的互斥元保護?
  • 是否所有操作需要同樣級別的保護?
  • 資料結構的一個小改變能否在不影響操作語義情況下提高併發性的機會?

所有的問題都被一個想法所指導:如何能夠最小化必然發生的序列化,並且能夠最大限度地實現併發性?

 

 

相關文章