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