日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入理解Memory Order

發布時間:2024/2/28 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解Memory Order 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

深入理解Memory Order

    • cpu 保證
    • cache
    • 編程技術
      • lock-free
      • wait-free
      • Read–modify–write
        • Compare-And-Swap(CAS)
          • cas原理
          • cas開銷
          • test-and-set
        • consensus member
      • wait-free
    • ABA problem
    • memory order
      • 背景知識
        • 延伸:`__asm volatile("" ::: "memory")`的含義
      • memory model
    • C++ atomic
      • memory_order
        • memory_order_relaxed
        • memory_order_consume
        • memory_order_acquire
        • memory_order_release
        • memory_order_acq_rel
        • memory_order_seq_cst
    • 術語
      • **Sequenced-before**
      • Carries dependency
      • Modification order
      • Release sequence
      • Synchronizes-with
      • Dependency-ordered before
      • **Inter-thread happens-before**
      • Happens-before
      • Visible side-effects
    • 編程實現
      • 操作組合完成原子操作
      • fense
        • atomic_thread_fence分類和效果
        • fence和同樣memory order的原子操作同步效果的區別
        • 利用fense進行同步
        • 費曼方法
    • linux kernel memory barriers閱讀筆記
    • 我們為什么要學習原子操作和弱內存序
    • Cacheline
    • 參考鏈接


cpu 保證

intel SDM Volume 3 8.1.1 Guaranteed Atomic Operations談到了,在intel平臺了,有一些內存操作是被處理器天然的保證原自性,不需要lock

cache

編程技術

lock-free

Lock free允許單獨的線程個體阻塞,但是會保證系統整體上的吞吐,如果一個算法對應的程序的線程在運行了足夠長時間的情況下,至少有一個線程取得了進展,那么我們說這個算法是lock-free的。

概括起來就是,如果涉及到共享內存的多線程代碼在多線程執行下不可能互相影響導致被hang住,不管OS如何調度線程,至少有一個線程在做有用的事,那么就是lock-free。使用了鎖的代碼肯定不是lock free,因為一個線程加鎖后如果被系統切出去了其他所有線程都處于等待中。但是沒用鎖也不一定是lock free,**因為普通的代碼邏輯也可能會導致一個線程hang住另一個線程。**鎖之所以在高并發的時候表現很差,主要原因就是加鎖的線程會hang住其他待加鎖的線程,lock-free可以很好的解決這一問題。

wait-free

Read–modify–write

read modify write是一系列原子操作,比如 cas, fetchadd, test-and-set

Compare-And-Swap(CAS)

  • CAS是樂觀鎖并且可能失敗,讀寫鎖是悲觀鎖

  • 類似c++11里的compare_exchange_strong

cas原理
  • 比較再交換, CAS有3個操作數,內存值V,舊的預期值A,要修改的新值B。當且僅當預期值A和內存值V相同時,將內存值V修改為B,否則什么都不做。

  • 如兩個線程去更改一個內存地址,則只會有一個成功。失敗的線程并不會被掛起,而是被告知這次競爭中失敗,并可以再次發起嘗試

  • 從粒度上而言,cas只能保證一個共享變量的原子性,如果對多個共享變量操作,要加鎖了

cas開銷

CAS(比較并交換)是CPU指令級的操作,只有一步原子操作,所以非???。但會有cache miss的開銷

  • 當 CPU 從內存中讀取一個變量到它的寄存器中時,必須首先將包含了該變量的緩存線讀取到 CPU 高速緩存。同樣地,CPU 將寄存器中的一個值存儲到內存時,不僅必須將包含了該值的cacheline讀到 CPU 高速緩存,還必須確保沒有其他 CPU 擁有該cacheline的拷貝。
test-and-set

textandset就是傳入兩個值與一個內存地址,讓比較值與內存地址中的值相比較,如果一樣就交換,不一樣就不交換。返回值是內存地址中的值,整個過程是原子的。通常用于實現自旋鎖

consensus member

Maurice Herlihy (1991) ranks atomic operations by their consensus numbers, as follows:

  • ∞: memory-to-memory move and swap, augmented queue, compare-and-swap, fetch-and-cons, sticky byte, load-link/store-conditional (LL/SC)[1]
  • 2n - 2: n-register assignment
  • 2: test-and-set, swap, fetch-and-add(FAA), queue, stack
  • 1: atomic read and atomic write

從上面可以看出, cas是無窮,fetch and add 是2

wait-free

single-reader-single-writer queue

ABA problem

如果內存地址V初次讀取的值是A,并且在準備賦值的時候檢查到它的值仍然為A,那我們就能說它的值沒有被其他線程改變過了嗎?

如果在這段期間它的值曾經被改成了B,后來又被改回為A,那CAS操作就會誤認為它從來沒有被改變過。這個漏洞稱為CAS操作的“ABA”問題。Java并發包為了解決這個問題,提供了一個帶有標記的原子引用類“AtomicStampedReference”,它可以通過控制變量值的版本(加一個version字段)來保證CAS的正確性。因此,在使用CAS前要考慮清楚“ABA”問題是否會影響程序并發的正確性,如果需要解決ABA問題,改用傳統的互斥同步可能會比原子類更高效。

memory order

memory order受編譯器和cpu運行時重排的影響。c++ 11后也正式引入了memory order的概念,c++的memory oder更多則是一種約定和方法,給程序員提供了一種跨平臺的通用方法來限制上述兩種重排,這也極大地方便了我們實現lock free算法,在此之前,程序員如果想要限制重排,可能需要手動調用不同平臺的專有fence。

背景知識

  • cpu優化
  • X86/64屬于強memory model的范疇,只可能發生Storeload reorder。原來在寫操作之后的讀操作重排到之前,并且Intel 64 Architectures Software Developer’s Manual, Volume 3, section 8.2.2指出,Reads may be reordered with older writes to different locations but not with older writes to the same location.
  • arm架構屬于弱memory model,四種重排都會發生,包括Loadload reorder、Loadstore reorder、Storeload reorder、Storestore reorder,只不過arm保證了數據依賴順序,在 Arm? Architecture Reference Manual Armv8, for Armv8-A architecture profile B2.2.3中提到:
    • All writes to the same location are serialized, meaning they are observed in the same order by all observers, although some observers might not observe all of the writes.
    • A read of a location does not return the value of a write until all observers observe that write.
  • 編譯器優化:
  • LINUX KERNEL MEMORY BARRIERS其中有個章節叫做Compiler barrier,主要講編譯器對memory order做出的優化,很多在單線程編程(uniprocessor)中沒有任何問題的優化,在并發編程(concurrent code)中會導致致命的錯誤,所以很多地方需要加編譯器屏障來顯示屏蔽編譯器優化。
  • 其中linux kernel中主要使用READ_ONCE()和WRITE_ONCE()對單條指令增加volatile語義,也可以對變量增加volatile定義給其增加volatile語義。
  • 另外也可以使用barrier()顯式的增加編譯器內存屏障,其作用相當于G++中的__asm volatile("" ::: "memory")
  • 延伸:__asm volatile("" ::: "memory")的含義

  • 這條語句后面的語句不能被編譯器優化到前面去,前面的不能被優化到后面去。這是所有內嵌匯編都具有的效果。
  • 所在函數不得被inline,不管開多高的優化等級, 這也是所有內嵌匯編都具有的效果。但是這一點目前也漸漸被gcc新版本打臉了。。
  • 重點,這條語句之后,函數返回前的所有流程(也就是包括了循環語句 跳轉到這條語句前面去的場景),對所有地址的訪問(包括局部變量地址)都必須去內存里去load,而不能使用這條語句前寄存器緩存的結果(當然,某些寄存器的結果編譯器還是認為還是有效的,例如堆棧寄存器,不然代碼沒法走下去了)。也就是這條語句后的代碼都含有volatile的語義。
  • 本節摘自朱元的知乎回答

    memory model

    對內存的操作可以概括為讀和寫,也就是load和store,因此reorder也就可以整體上分為以下四種類型

  • Loadload reorder:兩個讀操作之間重排
  • Loadstore reorder:原來在寫操作之前的讀操作重排到之后
  • Storeload reorder:原來在讀操作之前的寫操作重排到之后
  • Storestore reorder:兩個寫操作之間重排
  • X86/64(intel/AMD)屬于強memory model的范疇,只可能發生Storeload reorder。原來在讀操作之前的寫操作重排到之后,并且Intel 64 Architectures Software Developer’s Manual, Volume 3, section 8.2.2指出,Reads may be reordered with older writes to different locations but not with older writes to the same location.

    C++ atomic

    #include <atomic>

    如果使用atomic但是不用任何的成員函數,而是用自增,+=之類的操作符,那么相當于默認使用fetch_add,默認使用order:std::memory_order_seq_cst

    memory_order

    typedef enum memory_order {memory_order_relaxed,memory_order_consume,memory_order_acquire,memory_order_release,memory_order_acq_rel,memory_order_seq_cst } memory_order;

    memory_order_relaxed

    這個很好理解,寬松的內存序,指定為這個的所有原子操作就真的僅僅是保證自身的原子性,不會對任何其他變量的讀寫產生影響。如果確實不需要其他的內存同步,那么這是最好的選擇,比如原子計數器。

    memory_order_consume

    memory_order_consume適用于load operation,對于采用此內存序的load operation,我們可以稱為consume operation,設有一個原子變量M上的consume operation,對周圍內存序的影響是:當前線程中該consume operation后的依賴該consume operation讀取的值的load 或strore不能被重排到該consume operation前,其他線程中所有對M的release operation及其之前的對數據依賴變量的寫入都對當前線程從該consume operation開始往后的操作可見,相比較于下面講的memory_order_acquire,memory_order_consume只是阻止了之后有依賴關系的重排。絕大部分平臺上,這個內存序只會影響到編譯器優化,依賴于dependency chain。但實際上很多編譯器都沒有正確地實現consume,導致等同于acquire。

    memory_order_acquire

    memory_order_acquire適用于load operation,對于采用此內存序的load operation,我們可以稱為acquire operation,設有一個原子變量M上的acquire operation,對周圍內存序的影響是:當前線程中該acquire operation后的load 或strore不能被重排到該acquire operation前,其他線程中所有對M的release operation及其之前的寫入都對當前線程從該acquire operation開始往后的操作可見。

    memory_order_release

    memory_order_release適用于store operation,對于采用此內存序的store operation,我們可以稱為release operation,設有一個原子變量M上的release operation,對周圍內存序的影響是:該release operation前的內存讀寫都不能重排到該release operation之后。并且:

    • 截止到該release operation的所有內存寫入都對另外線程對M的acquire operation以及之后的內存操作可見,這就是release acquire 語義。
    • 截止到該operation的所有M所依賴的內存寫入都對另外線程對M的consume operation以及之后的內存操作可見,這就是release consume語義。

    memory_order_acq_rel

    memory_order_acq_rel適用于read-modify-write operation,對于采用此內存序的read-modify-write operation,我們可以稱為acq_rel operation,既屬于acquire operation 也是release operation. 設有一個原子變量M上的acq_rel operation:自然的,該acq_rel operation之前的內存讀寫都不能重排到該acq_rel operation之后,該acq_rel operation之后的內存讀寫都不能重排到該acq_rel operation之前. 其他線程中所有對M的release operation及其之前的寫入都對當前線程從該acq_rel operation開始的操作可見,并且截止到該acq_rel operation的所有內存寫入都對另外線程對M的acquire operation以及之后的內存操作可見。

    memory_order_seq_cst

    memory_order_seq_cst 可以用于 load operation,release operation, read-modify-write operation三種操作,用于 load operation的時候有acquire operation的特性,用于 store operation的時候有release operation的特性, 用于 read-modify-write operation的時候有acq_rel operation的特性,除此之外,有個很重要的附加特性,一個單獨全序,也就是所有的線程會觀察到一致的內存修改,也就是順序一致性的強保證。參考鏈接17講到了memory_order_seq_cst和memory_order_acq_rel的不同

    術語

    C++ memory order循序漸進(二)—— C++ memory order基本定義和形式化描述所需術語關系詳解

    熟悉了各種原子操作,這些術語就不難理解了

    Sequenced-before

    這個定義的是同一個線程內的一種根據表達式求值順序來的一種關系,完整的規則定義很復雜,可以參考http://en.cppreference.com/w/cpp/language/eval_order,其中最直觀常用的一條規則簡單來說如下:每一個完整表達式的值計算和副作用都Sequenced-before于下一個完整表達式的值計算和副作用。從而也就有以分號結束的語語句Sequenced-before于下一個以分號結束的語句,比如:

    r2 = x.load(std::memory_order_relaxed); // C y.store(42, std::memory_order_relaxed); // D

    從而有 C Sequenced-before D。

    Carries dependency

    Modification order

    Release sequence

    Synchronizes-with

    Dependency-ordered before

    這個關系是針對consume來的,對于分屬不同線程的賦值A和賦值B,如果他們之間有以下關系之一:

  • A對某個原子變量M做release操作,B對M做consume操作,并且B讀到了release sequence headed by A中的任意一個值。這條就是上面說的release sequence rule的關鍵。
  • A is dependency-ordered before X,并且 X carries dependency into B。前面說過了,carries dependency into是線程內的一種關系,這里就是X和B屬于同一線程,并且B對X有依賴。
    我們就說 A dependency-ordered before B。
  • Inter-thread happens-before

    Inter-thread happens-before,看字面意思就知道是定義了線程間賦值操作之間的關系,假如有線程1中的賦值操作A,線程2中的賦值操作B,如果滿足以下任意一條,那么有A inter-thread happens before B:

  • A synchronizes-with B
  • A dependency-ordered before B
  • A synchronizes-with 某個 evaluation X, 并且 X sequenced-before B
  • A sequenced-before 某個 evaluation X, and X inter-thread happens-before B
  • A inter-thread happens-before 某個evaluation X,并且X inter-thread happens-before B
  • Happens-before

    Visible side-effects

    編程實現

    要達到數據同步的效果,需要進行組合使用,我們可以在兩個地方指定memory order,一是atomic變量(原子變量)的操作,二是fence,利用fence可以不依賴原子變量進行同步

    操作組合完成原子操作

  • Relaxed ordering,所有的都是relaxed,沒有序的保證
  • Release-Acquire ordering 線程A使用release, 線程B使用acquire,所有happened-before A的內存寫入都對線程B acquire的操作可見
  • Release-Consume ordering 因為Release-Consume需要跟蹤依賴鏈,目前在很多編譯器實現上是直接等同于Release-Acquire的,并且從c++17標準開始, release-consume order還在修訂,并不推薦使用。
  • Sequentially-consistent ordering 使用memory_order_seq_cst可以獲得全局順序一致,是atomic變量默認的內存序,也是最強的保證,在如果形成了該內存序,除了有release acquire的效果,還會外加一個單獨全序,也就是保證所有的線程觀察到內存操作完全同樣的順序。,如果對性能有較高要求,不是特別必要不要使用這個內存序。
  • 仔細想想,原子操作其實存在兩個語義,一個是對當前線程限制重排,另一個是synchronized-with另外的線程

    如圖,那種沒有synchronized-with的關系,不會有visble side-effect

    fense

    #include <atomic> extern "C" void atomic_thread_fence( std::memory_order order ) noexcept;

    fence不光可以不依賴原子操作進行同步,而且相比較于同樣memory order的原子操作,具有更強的內存同步效果。無論是純粹基于原子操作的同步,還是利用fence的,最常用的兩種就是release acquire和Sequentially-consistent ordering

    atomic_thread_fence分類和效果

    和atomic變量類似,atomic_thread_fence也可以指定六種memory order,指定不同memory order的fence可以分為以下幾類:

  • std::atomic_thread_fence(memory_order_relaxed),沒有任何效果。
  • std::atomic_thread_fence(memory_order_acquire) 和 std::atomic_thread_fence(memory_order_consume) 屬于acquire fence。
  • std::atomic_thread_fence(memory_order_release)屬于release fence。
  • std::atomic_thread_fence(memory_order_acq_rel)既是acquire fence 也是release fence,為了方便這里稱為full fence
  • std::atomic_thread_fence(memory_order_seq_cst)額外保證有單獨全序的full fence。
  • fence和同樣memory order的原子操作同步效果的區別

    基于atomic_thread_fence(外加一個任意序的原子變量操作)的同步和基于原子操作的同步很類似,比如最常用的,都可以形成release acquire語義,但是從上面的描述可以看出,fence的效果要比基于原子變量的效果更強,在weak memory order平臺的開銷也更大。

    以release為例,對于基于原子變量的release opration,僅僅是阻止前面的內存操作重排到該release opration之后,而release fence則是阻止重排到fence之后的任意store operation之后,比如一個簡單的例子:

    std::string* p = new std::string("Hello"); ptr.store(p, std::memory_order_release);

    以下代碼具有同樣效果:

    std::string* p = new std::string("Hello"); std::atomic_thread_fence(memory_order_release); ptr.store(p, std::memory_order_relaxed);

    再比如:
    依賴ptr1的線程永遠能讀到正確值,但是依賴ptr2的不一定。

    std::string* p = new std::string("Hello"); ptr1.store(p, std::memory_order_release); ptr2.store(p, std::memory_order_relaxed);

    依賴ptr1和ptr2的的線程都永遠能讀到正確值

    std::string* p = new std::string("Hello"); std::atomic_thread_fence(memory_order_release); ptr1.store(p, std::memory_order_relaxed); ptr2.store(p, std::memory_order_relaxed);

    利用fense進行同步

    費曼方法

  • 原子操作首先根據memoryorder指定了當前線程的內存操作重排
  • 不同atomic/fense的組合,指定了不同線程間的同步方式(內存序)
  • 最重要的兩種內存序:Relase-Acquire orderingSequentially-consisent ordering
  • fense的效果比atomic要更好,但是開銷更大。release fence則是阻止重排到fence之后的任意store operation之后
  • linux kernel memory barriers閱讀筆記

  • linux上一般使用smp barrier。這種barrier在up系統的一般情況下上會退化為compile barrier
  • linux系統沒有上述高級語言的這么多種關系名詞,但是兩個線程形成的關系和高級語言的的關系大概相同
  • 內核里的READ_ONCE()和WRITE_ONCE()只對非volatile生效,volatile本身已經包含READ_ONCE()和WRITE_ONCE()的volatile語義
  • 我們為什么要學習原子操作和弱內存序

    本節摘自文章關于原子操作和弱內存序

    有人說這些東西是不是太底層了,平時是不是用不到這些知識。其實不是,除了上面所說的無鎖編程場景之外,至少以下幾種場景還是要用到的。

  • C和C++多線程編程,如果不了解弱內存序的知識,還是很可能會產生一些bug的,而且這些bug都很難定位。
  • 定位由于弱內存序產生的bug,即使是業界知名的軟件,比如mysql等一些軟件,在兼容ARM的過程中,由于弱內存序的問題,也會有很多bug,定位這些bug,也需要這方面的相關知識。
  • 如果一些軟件一開始只支持了X86,并且使用了底層的原子操作,你如果想要將這些軟件兼容ARM,并進行相關開發工作的話,你就要對這些原子操作匯編指令等等進行對應的移植,還要優化。這個時候也需要這方面的知識。比如我們團隊在移植Impala過程中的相關開發工作
  • 有時候有些軟件的內存序使用過于嚴格,也需要進行優化,會對軟件的性能有一定的提升。比如我們團隊大牛在mysql上的一些優化工作,就是針對這方面的,比如有些原子變量的自增,并不需要依賴上下文,所以就可以不需要嚴格的內存屏障語義??梢詤⒖?#xff1a;
  • https://bugs.mysql.com/bug.php?id=99432 https://bugs.mysql.com/bug.php?id=100119 https://bugs.mysql.com/bug.php?id=100432 https://bugs.mysql.com/bug.php?id=100060 https://bugs.mysql.com/bug.php?id=100132

    Cacheline

    沒有任何競爭或只被一個線程訪問的原子操作是比較快的,“競爭”指的是多個線程同時訪問同一個cacheline?,F代CPU為了以低價格獲得高性能,大量使用了cache,并把cache分了多級。百度內常見的Intel E5-2620擁有32K的L1 dcache和icache,256K的L2 cache和15M的L3 cache。其中L1和L2 cache為每個核心獨有,L3則所有核心共享。一個核心寫入自己的L1 cache是極快的(4 cycles, ~2ns),但當另一個核心讀或寫同一處內存時,它得確認看到其他核心中對應的cacheline。對于軟件來說,這個過程是原子的,不能在中間穿插其他代碼,只能等待CPU完成一致性同步,這個復雜的硬件算法使得原子操作會變得很慢,在E5-2620上競爭激烈時fetch_add會耗費700納秒左右。訪問被多個線程頻繁共享的內存往往是比較慢的。比如像一些場景臨界區看著很小,但保護它的spinlock性能不佳,因為spinlock使用的exchange, fetch_add等指令必須等待最新的cacheline,看上去只有幾條指令,花費若干微秒并不奇怪。

    要提高性能,就要避免讓CPU頻繁同步cacheline。這不單和原子指令本身的性能有關,還會影響到程序的整體性能。最有效的解決方法很直白:盡量避免共享。

    • 一個依賴全局多生產者多消費者隊列(MPMC)的程序難有很好的多核擴展性,因為這個隊列的極限吞吐取決于同步cache的延時,而不是核心的個數。最好是用多個SPMC或多個MPSC隊列,甚至多個SPSC隊列代替,在源頭就規避掉競爭。
    • 另一個例子是計數器,如果所有線程都頻繁修改一個計數器,性能就會很差,原因同樣在于不同的核心在不停地同步同一個cacheline。如果這個計數器只是用作打打日志之類的,那我們完全可以讓每個線程修改thread-local變量,在需要時再合并所有線程中的值,性能可能有幾十倍的差別。

    一個相關的編程陷阱是false sharing:對那些不怎么被修改甚至只讀變量的訪問,由于同一個cacheline中的其他變量被頻繁修改,而不得不經常等待cacheline同步而顯著變慢了。多線程中的變量盡量按訪問規律排列,頻繁被其他線程修改的變量要放在獨立的cacheline中。要讓一個變量或結構體按cacheline對齊

    參考鏈接

  • 并發編程—CAS(Compare And Swap)
  • wait-free是指什么?
  • 深入淺出cache寫策略
  • C++ memory order循序漸進(一)—— 多核編程中的lock free和memory model系列文章,本文很多內容摘自這系列文章
  • Read–modify–write wiki
  • Consensus (computer science)一致性, 類似于zk集群的選舉和數據同步,必須有一半以上同意
  • CAS原理
  • 什么是樂觀鎖,什么是悲觀鎖
  • std::atomic::fetch_add
  • std::memory_order 本文很多內容翻譯自這里
  • preshingNB
  • The Synchronizes-With Relation
  • Fences with non-atomics in C11
  • C++ memory order循序漸進(五)—— C++ memory order在編譯器和cpu層面的具體實現
  • volatile與內存屏障總結 - 知乎
  • Does atomic_thread_fence(memory_order_seq_cst) have the semantics of a full memory barrier?
  • How do memory_order_seq_cst and memory_order_acq_rel differ?
  • LINUX KERNEL MEMORY BARRIERS最近看到里面的章節SMP Barrier Pairing感覺還是講的不錯的
  • Symmetric multiprocessingsmp現代計算機,指多核心的cpu, up(uniprocessor)單核cpu。對上條里面的smp的解釋
  • 6.47.2 Extended Asm - Assembler Instructions with C Expression Operandsgcc中的asm編程指南
  • boost對于atomic fense對應的asm語句
  • LWN:怕不怕編譯器優化讓你的代碼徹底亂套? Load tearing會在編譯器用多個load指令來實現一次數據訪問
  • 如何理解 C++11 的六種 memory order?陳文禮的回答還是挺好的,我也是看懂了vhost_gate的問題之后才明白。
  • X86/GCC memory fence的一些見解作者列舉了例子,說明了為什么Compiler Fence在某些情況下是難以勝任的。
  • 如何使用屏障指令內核中的[w,r]mb和smp_[w,r]mb等等詳細介紹
  • C/C++ Volatile關鍵詞深度剖析
  • 多核Cache一致性緩存一致性 多核Cache一致性由硬件保證,對軟件來說是透明的。
  • 關于原子操作和弱內存序寫的挺好的
  • Understanding Memory-Barrier with MySQL EventMutex
  • 總結

    以上是生活随笔為你收集整理的深入理解Memory Order的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。