Go和C語言的32 位的無鎖、併發、通用佇列的原始碼

banq發表於2022-05-16

在考慮併發佇列設計時,我想到了一個通用的、無鎖的佇列,它適合於32位整數。這個佇列是 "通用 "的,因為一個單一的實現支援任何任意型別的元素,儘管它是用C語言實現的。它是無鎖的,因為它保證了全系統的進度。它一次最多可以儲存32,767個元素--對於必須始終保持約束的訊息佇列來說,這已經足夠了。

我將首先介紹一個單消費者、單生產者的佇列,然後以一定的代價將支援擴充套件到多個消費者。

佇列只有32位,怎麼能儲存這麼多元素?它只處理一個迴圈緩衝區的索引。呼叫者負責分配和操作佇列的儲存,在單一消費者的情況下,這不需要任何花哨的東西。同步是由佇列管理的。

像一個典型的圓形緩衝區,它有一個頭部索引和一個尾部索引。頭部是下一個要推送的元素,而尾部是下一個要彈出的元素。佇列儲存必須有兩個冪的長度,但容量比長度少一個。如果頭和尾相等,那麼佇列就是空的。這就 "浪費 "了一個元素,這就是為什麼容量比儲存的長度少一個。因此,這種設計已經有了一些明顯的限制,但我相信這種佇列的主要用例--用於CPU繫結的作業佇列--對這些限制沒有問題。

由於這是一個併發的佇列,值得注意的是儲存元素的 "所有權"。消費者擁有從尾部到頭部的元素,但不包括頭部。生產者擁有其他一切。推送和彈出都涉及一個 "提交 "步驟,將一個元素的所有權轉移到另一個執行緒。沒有元素被同時訪問,這使得任何一個呼叫者的事情都很容易。

單消費者佇列和多消費者佇列都支援:
  • 原子:C11、GNU、MSC
  • 執行緒:pthreads,win32
  • 編譯器:GCC、Clang、MSC
  • 主機:Linux、Windows、BSD


原始碼:queue.c
C 和 Go 之間共享的併發佇列:queue.go

相關文章