Interlocked API的原子性如何保證

2021-08-22 19:49:47 字數 1207 閱讀 5257

前面的文章提到如何利用interlocked api設計系統級日誌。interlocked api可以對在多執行緒之間共享的記憶體變數提供原子性訪問。有些cpu在硬體層面上直接支援這些操作,如80386以後的x86架構cpu,xchg、xadd、cmpxchg等指令在進行記憶體訪問時鎖住匯流排。舉例來說, interlockedexchangeadd在x86上的實現如下:

longwinapiinterlockedexchangeadd(plongaddend,longvalue)

}直接利用了xadd指令完成交換。

問題是,其他架構的cpu沒有提供類似的指令可以鎖定匯流排,interlocked api的原子性如何保證?拿arm架構來說,在windows ce上interlockedexchangeadd的arm實現如下:

leaf_entryinterlockedexchangeadd

ldrr12,[r0]

addr2,r12,r1

strr2,[r0]

movr0,r12;(r0)=returnoriginalvalue

bxlr

entry_endinterlockedexchangeadd

翻譯成c語言就是:

longinterlockedexchangeadd(plongaddend,longvalue)

完全是乙個普通的函式。在多執行緒環境下,這樣的實現是不足以保證原子性的。舉個例子,你有乙個全域性變數g_lvar,執行緒1和執行緒2會改變它的值:

longg_lvar=0;

voidthread_entry()

在interlockedexchange不能保證原子性的情況下會出現什麼問題?正常情況下,兩個執行緒執行完thread_entry函式後,g_lvar的值為2。現在設想一下這種情況:執行緒1執行完interlockedexchangeadd中的第一句(此時oldval為0),時間片剛好用完,執行緒排程器喚醒執行緒2,執行緒2執行順利執行完thread_entry,g_lvar為1。執行緒排程器切換回到執行緒1執行,由於執行緒1中本地變數oldval為0,*target=newval=oldval+value=0+1=1,因此執行緒1的thread_entry完成後,g_lvar的值仍然為1!!問題處在interlockedexchangeadd的執行可能被別的執行緒打斷,導致運算元有可能被其他執行緒改變,而interlockedexchangeadd本身無法預知這一點,也就是說interlockedexchangeadd的原子性無法得到保證。

container of 的的的原理

另外一篇,同樣精彩,揭開linux核心中container of的神秘面紗 華清遠見嵌入式學院講師。在linux 核心中有乙個大名鼎鼎的巨集container of 這個巨集是用來幹嘛的呢?我們先來看看它在核心中是怎樣定義的。呵呵,乍一看不知道是什麼東東。我們先來分析一下container of p...

存在的就是合理的,發生的即是必然的。

筆者有時候會想,什麼是對,什麼是錯?對於追求某一件事情之前首先會考慮,為什麼我要做這件事情。所以經過自我分析和生活周邊環境的總結。我認為,對於乙個人來,這是在站在個體的角度上說。什麼是對的?就是你自己覺得是對的,它就是對的。不過這個只是你自己的想法。主觀上的正確,不代表客觀上也受到了別人的認可。就拿...

Apache的rewrite的重寫相關的引數

apache mod rewrite規則重寫的標誌一覽 使用mod rewrite時常用的伺服器變數 rewriterule規則表示式的說明 匹配任何單字元 chars 匹配字串 chars chars 不匹配字串 chars text1 text2 可選擇的字串 text1或text2 匹配0到1...