這個問題的靈感來自Lock-free Progress Guarantees。顯示的代碼不是嚴格無鎖的。每當佇列不為空或未滿時暫停寫入執行緒,讀取執行緒就會回傳 false,從而阻止整個資料結構繼續進行。
對于真正的無鎖環形緩沖區,正確的行為應該是什么?
通常,真正的無鎖演算法涉及一個被搶占的執行緒實際上試圖幫助其他執行緒完成操作的階段。
對這種技術有任何參考嗎?如何為基于陣列的 MPMC 佇列實作它?
我查看了一些代碼,它們也有類似的問題。
- craflin 的版本使用兩個內部原子來記錄讀取和寫入。
- https://codereview.stackexchange.com/questions/263157/c-lock-free-mpmc-ring-buffer-in-c20使用忙等待,而不是無鎖。
uj5u.com熱心網友回復:
作為一個很好的例子,說明跨執行緒輔助通常如何在現實生活中發揮作用,考慮可以通過liblfds按照以下方式更改演算法來獲得無鎖 MPMC 佇列:
使用 3 個計數器:
alloc_pos:已啟動的推送操作總數。當推送開始時,它會自動遞增。write_pos: 所有較低位置的寫操作都被認為是完整的。read_pos:已知寫在較低位置的所有專案都已被消耗。
在此方案中,推送或彈出操作由受影響插槽中的 CAS 完成。write_pos和read_pos變數是多余的。
因此,要推送,執行緒首先遞增alloc_pos,然后遞增write_pos超過它前面所有可以看到已完成的槽。這是一個輔助——它正在完成之前在其他執行緒中開始的寫入。然后執行緒必須掃描 和 之間的插槽write_pos,alloc_pos直到找到一個空閑的插槽并設法使用 CAS 保留它。
要彈出,閱讀器首先遞增read_pos所有寫在它可以看到被消耗的較低位置的專案。這又是一個幫助——完成以前的閱讀。然后它從read_posto掃描alloc_pos以查看是否可以找到已完成寫入的專案。
正如評論中提到的那樣,真正做到這一點會很煩人,實施決策會權衡性能與您需要的排序和可用性保證,以及跳過箍來防止 ABA 問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/457402.html
