contributed by < Eddielin0926 >
lfring
是個 lock-free ring buffer 實作,並支援 multiple-producer/multiple-consumer (MPMC)
Question | Answer |
---|---|
DDD | idx++; |
KKK | mask + 1 |
TTT | &lfr->ring[tail & mask].idx, __ATOMIC_ACQUIRE |
HHH | head + actual |
這個程式是生產者消費者問題的實作,以有限環狀鏈結串列解決緩衝區問題。
從 tests.c
的 main
開始理解,可以看到 main
是由四種測試狀況構成的,分別是 multiple producer multiple consumer (MPMC), multiple producer single consumer (MPSC), single producer multiple consumer (SPMC), single producer single consumer (SPSC)。
test_ringbuffer
的參數 flag
會決定測試的生產者消費者組合,有四種前綴是 LFRING_FLAG_
的 enum,用最低的兩個位元來決定情況。
在 test_ringbuffer
中可以看到 flags
是作為 lfring_alloc
的參數,會存放在 lfring
中。ROUNDUP_POW2
會將 n_elems
近似至 2 的指數倍,用來決定要分配多少記憶體空間,最後初始化結構體中的成員。
在分配記憶體空間時,使用的是 oscal_alloc
,因為 aligment
是 64,因此實際上使用的是 aligned_alloc
,aligned_alloc
會讓非配到的記憶體空間對齊 alignment
,舉例來說,這邊的 alignment
是 64,因此初始的記憶體位址最低 6 位都會是 0。
ROUNDUP(a, b)
會讓 a
去近似 b
的倍數。
ALIGNED(CACHE_LINE)
會展開成 __attribute__((__aligned__(64)))
要求編譯器在分配空間時對齊 64 byte。
restrict
關鍵字告訴編譯器所有對該位址的操作都會通過該指標,使編譯器更好的進行優化。
考慮到多執行續的情況,在讀取 lfr->tail
時使用了 __atomic_load_n
來會保證位址在讀取不會被其他執行緒打斷而造成指標的值被影響,可以參考並行程式設計: Atomics 操作和 Atomic vs. Non-Atomic Operations 來理解當沒有使用 atomic
操作時可能會造成的結果。
tail & mask
是因為 tail
對齊 cache line,所以與 mask
做 AND 可以當作 index 來使用。