DPDK 無鎖操作如何保證原子?

2021-09-19 05:30:48 字數 1267 閱讀 4395

rte_atomic32_cmpset()稱為cas(compare and set)操作,是dpdk無鎖佇列實現的關鍵函式,**如下:

static inline int

rte_atomic32_cmpset(volatile uint32_t *

dst, uint32_t

exp, uint32_t

src)

輸入運算元為*dst(memory記憶體)、exp(存放於eax暫存器)、src(任意可用通用暫存器)

cas有3個運算元,記憶體值*dst,舊的預期值exp,要修改的新值src, 當且僅當預期值exp和記憶體值*dst相同時,將記憶體值*dst修改為src,否則什麼都不做。

這個函式是如何保證cas原子操作的呢?

mplocked字首就是鎖匯流排,該字首後面的指令編譯成機器碼後就可以使cpu在執行這條指令的時候把#hlock pin的電位拉低,持續到這條指令結束時放開,從而把匯流排鎖住,這樣別的cpu就暫時不能通過該匯流排訪問記憶體了,確保同一時間只有乙個cpu執行緒能操作這塊記憶體。

cmpxchgl指令就是被lock住匯流排的指令,用於比較並交換運算元,這個指令是原子的。cmpxchgl比較eax(也就是exp)與 *dst的值,如果相等,那麼將src的值賦值給*dst,同時標誌暫存器zf位置1;否則,將*dst的值賦值給eax,並且將標誌暫存器zf位置0。

寫完之後,通過cache一致性協議保證所有其他cpu看到同一塊實際記憶體值的更新

sete,如果標誌暫存器zf位為1,那麼設定res為1否則設定為0

:」memory」 是優化屏障,防止編譯器優化有順序要求的**

目標記憶體dst必須是volatile 修飾的,編譯器每次遇到這個變數都從記憶體讀值,而不從cpu自己的快取或暫存器讀值。

"=a"指定output operand應遵守的約束(constraint),res為存放指令結果的變數

「a」表示先將命令執行結果輸出至eax暫存器,然後再由eax更新位於記憶體中的res

如果這時候eax已經被使用,那怎麼辦?

其實很簡單:因為gcc 知道eax 已經被使用,它在這段彙編**

的起始處插入一條語句pushl %eax,將eax 內容儲存到堆疊,然

後在這段**結束處再增加一條語句popl %eax,恢復eax的內容

"=m"表示不通過暫存器中轉,而是直接操作記憶體

"r" 將輸入變數放入通用暫存器,也就是eax,ebx,ecx,edx,esi,edi中的乙個

volatile + lock +  cmpxchgl指令 + 快取一致性模型 + 優化屏障 = 原語cas

dpdk無鎖環形佇列的使用

入口使用dpdk,資料報解包分析後續處理執行緒效能太低,cpu很大一部分浪費在多執行緒鎖開銷上,於是想用dpdk無鎖佇列,看是否有改善。使用前不知道dpdk的ring是否能在收發包之外使用,也沒找到實際使用跟收發包無關的例子 也不需要使用mbuf,需要儲存乙個指標的佇列,直接拿過來用看看可不可以。前...

linux無鎖話程式設計,原子

linux支援的哪些操作是具有原子特性的?知道這些東西是理解和設計無鎖化程式設計演算法的基礎。下面的東西整理自網路。先感謝大家的分享!sync fetch and add系列的命令,發現這個系列命令講的最好的一篇文章,英文好的同學可以直接去看原文。multithreaded data type ac...

無鎖工具類 原子類

累加器例子 add10k 這個方法不是執行緒安全的,問題就出在變數 count 的可見性和 count 1 的原子性上 1.可見性問題可以用 volatile 來解決,2.原子性問題我一直都是採用的互斥鎖。public class test 對於簡單的原子性問題,還有一種無鎖方案 1.將原來的 lo...