簡體   English   中英

我是否需要使用內存屏障來保護共享資源?

[英]Do I need to use memory barriers to protect a shared resource?

在多生產者,多消費者的情況下。 如果生產者寫入int a ,並且消費者正在讀取int a ,我是否需要圍繞int a內存屏障?

我們都了解到:共享資源應該始終受到保護,標准不能保證正確的行為。

然而,在高速緩存一致的體系結構上,可以自動確保可見性,並且保證8,16,32和64位變量的原子性MOV操作。

因此,為什么要保護int a

至少在C ++ 11(或更高版本)中,您不需要(明確地)使用互斥鎖或內存屏障保護您的變量。

您可以使用std::atomic來創建原子變量。 對該變量的更改保證跨線程傳播。

std::atomic<int> a;

// thread 1:
a = 1;

// thread 2 (later):
std::cout << a;    // shows `a` has the value 1.

當然,還有更多的東西 - 例如,不能保證std::cout原子地工作,所以你可能必須保護它(如果你試圖從多個線程寫入,無論如何)。

然后由編譯器/標准庫來確定處理原子性要求的最佳方法。 在確保高速緩存一致性的典型體系結構中,它可能僅僅意味着“不要在寄存器中分配此變量”。 它可能會造成內存障礙,但只能在真正需要它們的系統上實現。

然而,在高速緩存一致的體系結構上,可以自動確保可見性,並且保證8,16,32和64位變量的原子性MOV操作。

除非您嚴格遵守C ++規范的要求以避免數據爭用,否則編譯器沒有義務按照它的方式使您的代碼功能化。 例如:

int a = 0, b = 0; // shared variables, initialized to zero

a = 1;
b = 1;

假設您在完全緩存一致的架構上執行此操作。 在這樣的硬件上,似乎因為a是在b之前編寫的,所以沒有線程將能夠看到值為1的b而沒有具有該值。

但這種情況並非如此。 如果您未能嚴格遵守C ++內存模型的要求以避免數據爭用,例如,如果沒有在任何地方插入正確的同步原語而讀取這些變量,那么您的程序實際上可能會在a之前觀察到b被寫入。 原因是您已經引入了“未定義的行為”,並且C ++實現沒有義務對您做任何有意義的事情。

在實踐中可能發生的是, 編譯器可能會重新排序寫入,即使硬件非常難以使其看起來好像所有寫入都按照執行寫入的機器指令的順序發生。 您需要整個工具鏈才能進行合作,而僅僅通過硬件進行協作(例如強大的緩存一致性)是不夠的。


如果您想了解C ++內存模型的細節並在C ++中編寫可移植的並發代碼,那么C ++ Concurrency in Action是一個很好的資源。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM