1. MEMORY_BARRIER的正確用法
為了更好的說明問題,這里只討論讀寫內(nèi)存柵欄,關(guān)于讀內(nèi)存柵欄、寫內(nèi)存柵欄可以看我發(fā)的文檔。 以下為簡化的偽代碼,這是唯一正確的MEMORY_BARRIER用法:
//生產(chǎn)者(對應(yīng)原來的PUSH接口):
PUT(data)
{
if (writeCusor + 1 != readCusor)
{
dataBuffer[writeCusor] = data;
MEMORY_BARRIER();
writeCusor++;
}
}
//消費者(對應(yīng)原來的POP接口):
GET(data)
{
if (readCusor != writeCusor)
{
data = dataBuffer[readCusor];
MEMORY_BARRIER();
readCusor++;
}
}
2. MEMORY_BARRIER的語義
MEMORY_BARRIER原語的語義為: 保證MEMORY_BARRIER之前的所有讀寫操作都在MEMORY_BARRIER之后的指令之前完成,并且所有CPU核看到都是這樣的順序。
2. 5G L2的代碼存在的問題
5G L2的代碼中,GET(data)接口的MEMORY_BARRIER()位置是這樣的:
GET(data)
{
if (readCusor != writeCusor)
{
MEMORY_BARRIER();
data = dataBuffer[readCusor];
readCusor++;
}
}
這里假定(1)語句中的readCusor變量受(2)語句中的加加操作影響,編譯器和CPU會自動識別,不會對這兩行代碼做優(yōu)化、調(diào)整,會嚴(yán)格按照字面順序執(zhí)行。
(1) data = dataBuffer[readCusor];
(2) readCusor++;
這樣的假定是存在問題的,因為編譯器或CPU可能會“優(yōu)化”成下面這樣:
GET(data)
{
if (readCusor != writeCusor)
{
MEMORY_BARRIER();
readCusorTemp = readCusor;
readCusor++;
data = dataBuffer[readCusorTemp];
}
}
這樣在生產(chǎn)者PUT那邊會先看到readCusor++,會在隊列滿的情況下,概率出現(xiàn)GET數(shù)據(jù)被覆蓋的情況。 雖然概率低,但一出問題就是嚴(yán)重甚至致命問題。