2020-03-12

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)重甚至致命問題。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容