本文是基于單生產(chǎn)者單消費(fèi)者線程的實現(xiàn)。
struct {
char buf[65536];
unsigned short writer_index;
unsigned short reader_index;
}
reader_index只由讀線程改變,writer_index只由寫線程改變。
讀線程讀取reader_index到writer_index之間的數(shù)據(jù),讀取完畢向前移動reader_index。發(fā)現(xiàn)writer_index小于reader_index,讀線程讀取數(shù)據(jù)直到隊列結(jié)尾,并將reader_index移到隊列開頭,繼續(xù)讀取。
寫線程計算檢查可用寫空間,將數(shù)據(jù)寫入,并移動writer_index。當(dāng)寫到隊列結(jié)尾,將writer_index移動到隊列開頭,再從頭開始寫。
讀線程看到的writer_index不一定是最新的,但不會導(dǎo)致讀取錯誤數(shù)據(jù),只是會比應(yīng)該讀取的少讀一些。
寫線程看到的reader_index不一定是最新的,但不會導(dǎo)致寫入錯誤,只是會比應(yīng)該寫入的少寫一些。
需要注意的是cpu對指令的亂序執(zhí)行以及cpu間cache同步亂序問題。
1.cpu完全可以先將寫指針移動,然后再寫入數(shù)據(jù),這樣的執(zhí)行順序?qū)τ趩尉€程沒有任何影響。對于我們現(xiàn)在這種模型,讀線程就有機(jī)率讀取到錯誤的數(shù)據(jù)。同樣讀線程先執(zhí)行讀指針移動,后讀取數(shù)據(jù),會有機(jī)率導(dǎo)致還沒有讀出的數(shù)據(jù)被寫線程寫入覆蓋。
2.cpu間數(shù)據(jù)同步數(shù)據(jù)可能亂序。比如cpu1修改了a和b,同步給cpu2,a和b到達(dá)cpu2的順序不確定。如果讀線程寫線程分處于兩個不同cpu執(zhí)行,有機(jī)率出現(xiàn)1問題中同樣的錯誤,即讀線程先看到了寫指針的改變,并讀取了還沒有被寫入的臟數(shù)據(jù)。
解決方法就是給cpu使絆,使用memory barrier(內(nèi)存屏障)讓cpu必須順序執(zhí)行指令,并保證同步順序。關(guān)于memory barrier的用法可以自行g(shù)oogle,也可以關(guān)注我的下一篇關(guān)于內(nèi)存屏障的使用介紹。