最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++內(nèi)存序的操作方法

 更新時間:2025年11月04日 09:29:54   作者:2301_80355452  
在C++中,內(nèi)存序(Memory Order)是一個非常重要的概念,特別是在多線程編程中,本文通過實例代碼介紹C++內(nèi)存序的相關(guān)知識,感興趣的朋友一起看看吧

1.為什么需要內(nèi)存序?

問題的根源:現(xiàn)代CPU的亂序執(zhí)行

// 從程序員角度看是順序執(zhí)行
int x = 0, y = 0;
void thread1() {
    x = 1;  // 步驟1
    y = 1;  // 步驟2
}
void thread2() {
    if (y == 1) {
        assert(x == 1);  // 可能失??!
    }
}

實際執(zhí)行可能:

  • CPU為了優(yōu)化,可能先執(zhí)行 y = 1,后執(zhí)行 x = 1
  • 編譯器也可能重排指令
  • 導(dǎo)致線程2看到 y == 1 但 x == 0

2.六種內(nèi)存序詳解

內(nèi)存序概覽表

內(nèi)存序作用使用場景性能
relaxed只保證原子性計數(shù)器、統(tǒng)計最快
consume數(shù)據(jù)依賴排序指針發(fā)布較快
acquire加載屏障讀側(cè)同步中等
release存儲屏障寫側(cè)同步中等
acq_rel加載+存儲屏障CAS操作較慢
seq_cst全序屏障默認,最安全最慢

3.逐層深入理解

3.1memory_order_relaxed- 最寬松

#include <atomic>
#include <thread>
#include <iostream>
std::atomic<int> x(0), y(0);
void relaxed_example() {
    // 線程1
    std::thread t1([](){
        x.store(1, std::memory_order_relaxed);  // 可能重排
        y.store(1, std::memory_order_relaxed);  // 可能重排
    });
    // 線程2
    std::thread t2([](){
        int r1 = y.load(std::memory_order_relaxed);  // 可能看到y(tǒng)=1但x=0
        int r2 = x.load(std::memory_order_relaxed);
        std::cout << "y=" << r1 << ", x=" << r2 << std::endl;
    });
    t1.join(); t2.join();
}

適用場景:

// 計數(shù)器 - 順序不重要,只要原子就行
std::atomic<int> counter(0);
void increment() {
    counter.fetch_add(1, std::memory_order_relaxed);
}

3.2memory_order_acquire和memory_order_release- 配對使用

#include <atomic>
#include <thread>
#include <cassert>
std::atomic<bool> flag{false};
int data = 0;
void producer() {
    data = 42;                                  // 1. 準備數(shù)據(jù)
    flag.store(true, std::memory_order_release); // 2. 發(fā)布標志(保證1在2之前)
}
void consumer() {
    while (!flag.load(std::memory_order_acquire)) { // 3. 獲取標志(保證4在3之后)
        // 等待
    }
    assert(data == 42);  // 4. 讀取數(shù)據(jù)(這里一定能看到42?。?
}

屏障效果圖示:

線程A (Producer)        線程B (Consumer)
data = 42
    ↓ (release屏障)
flag = true
                ─────→   while(!flag)
                            ↓ (acquire屏障)
                         assert(data==42) ?

3.3memory_order_acq_rel- 讀改寫操作

class SpinLock {
    std::atomic<bool> locked{false};
public:
    void lock() {
        // 期望locked=false,設(shè)置locked=true
        // 需要同時保證acquire和release語義
        while (locked.exchange(true, std::memory_order_acq_rel)) {
            // 自旋等待
        }
    }
    void unlock() {
        locked.store(false, std::memory_order_release);
    }
};

為什么需要acq_rel:

std::atomic<int> shared{0};
int normal_data = 0;
void thread_work() {
    // 修改前操作
    normal_data = 100;
    // CAS操作:既有讀又有寫
    int expected = 0;
    if (shared.compare_exchange_strong(expected, 1, 
                                      std::memory_order_acq_rel)) {
        // 成功:相當于acquire,能看到之前的修改
        // 同時:相當于release,保證之前的修改對其他線程可見
    }
}

3.4memory_order_seq_cst- 順序一致性(默認)

std::atomic<int> x{0}, y{0};
void sequential_example() {
    std::thread t1([](){
        x.store(1, std::memory_order_seq_cst);  // 1
        y.store(1, std::memory_order_seq_cst);  // 2
    });
    std::thread t2([](){
        int r1 = y.load(std::memory_order_seq_cst);  // 3
        int r2 = x.load(std::memory_order_seq_cst);  // 4
        // 所有線程看到相同的操作順序
        // 可能的順序:1→2→3→4 或 1→3→2→4 等
        // 但所有線程對順序的理解一致
    });
    t1.join(); t2.join();
}

4.在shared_ptr中的實際應(yīng)用

您代碼中的內(nèi)存序分析:

void release() {
    if (ref_count && ref_count->fetch_sub(1, std::memory_order_acq_rel) == 1) {
        delete ptr;
        delete ref_count;
    }
}
// 為什么用 memory_order_acq_rel?

詳細解釋:

class shared_ptr {
    void release() {
        // fetch_sub是讀-修改-寫操作:
        // 1. 讀取當前值 (需要acquire語義)
        // 2. 減去1
        // 3. 寫回新值 (需要release語義)
        // 使用acq_rel確保:
        if (ref_count && 
            ref_count->fetch_sub(1, std::memory_order_acq_rel) == 1) {
            // ↓ 這個delete操作必須看到ptr的所有修改
            delete ptr;     // 需要acquire保證看到完整對象狀態(tài)
            delete ref_count;
            // 同時,在delete之前的所有對象修改
            // 必須對其他線程可見 (release語義)
        }
    }
};

5.內(nèi)存序的層次關(guān)系

從弱到強的約束:

relaxed (最弱)
   ↓
consume
   ↓  
acquire/release
   ↓
acq_rel
   ↓
seq_cst (最強)

6.實際編程建議

6.1什么時候用什么內(nèi)存序

// 情況1:簡單計數(shù)器
std::atomic<int> counter{0};
counter.fetch_add(1, std::memory_order_relaxed);  // ?
// 情況2:標志位同步
std::atomic<bool> ready{false};
int data;
// 生產(chǎn)者
data = compute_data();
ready.store(true, std::memory_order_release);     // ?
// 消費者  
while (!ready.load(std::memory_order_acquire)) {} // ?
use_data(data);
// 情況3:復(fù)雜的同步邏輯(不確定時)
std::atomic<int> state{0};
state.compare_exchange_strong(old_val, new_val, 
                             std::memory_order_seq_cst);  // ? 安全第一

6.2實用示例:無鎖隊列

template<typename T>
class LockFreeQueue {
    struct Node {
        T data;
        std::atomic<Node*> next;
    };
    std::atomic<Node*> head, tail;
public:
    void push(const T& value) {
        Node* new_node = new Node{value, nullptr};
        Node* old_tail = tail.load(std::memory_order_acquire);
        while (!tail.compare_exchange_weak(old_tail, new_node,
                                          std::memory_order_acq_rel,
                                          std::memory_order_acquire)) {
            // CAS失敗,重試
        }
        // 鏈接節(jié)點
        old_tail->next.store(new_node, std::memory_order_release);
    }
};

7.測試和驗證

內(nèi)存序錯誤的檢測:

#include <atomic>
#include <thread>
#include <cassert>
std::atomic<int> x{0}, y{0};
int r1, r2;
void memory_order_test() {
    std::thread t1([](){
        x.store(1, std::memory_order_relaxed);
        y.store(1, std::memory_order_relaxed);
    });
    std::thread t2([](){
        r1 = y.load(std::memory_order_relaxed);
        r2 = x.load(std::memory_order_relaxed);
    });
    t1.join(); t2.join();
    // 在relaxed順序下,可能發(fā)生:
    // r1 == 1 (y已設(shè)置) 但 r2 == 0 (x還未設(shè)置)
    std::cout << "Result: r1=" << r1 << ", r2=" << r2 << std::endl;
}

8.總結(jié)

關(guān)鍵要點:

  • relaxed:只保證原子性,不保證順序
  • acquire/release:配對使用,建立線程間happens-before關(guān)系
  • acq_rel:用于讀-修改-寫操作,兼具兩者特性
  • seq_cst:全局順序,最安全但性能最差

使用建議:

  • 初學(xué)者:先用 seq_cst,確保正確性
  • 性能優(yōu)化:在理解的基礎(chǔ)上使用更寬松的內(nèi)存序
  • shared_ptr場景acq_rel 是正確的選擇
  • 標志同步acquire/release 是最佳選擇

您的shared_ptr實現(xiàn)中使用的 memory_order_acq_rel 是非常合適的,它確保了在釋放資源時能夠看到對象的完整狀態(tài),同時也保證了對象修改對其他線程的可見性。

到此這篇關(guān)于C++內(nèi)存序的操作方法的文章就介紹到這了,更多相關(guān)C++內(nèi)存序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 記逆向小白的第一次vbsedit 9爆破及內(nèi)存補丁制作過程

    記逆向小白的第一次vbsedit 9爆破及內(nèi)存補丁制作過程

    這篇文章主要介紹了記逆向小白的第一次vbsedit 9爆破及內(nèi)存補丁制作過程,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • 詳解如何利用C++實現(xiàn)Mystring類

    詳解如何利用C++實現(xiàn)Mystring類

    這篇文章主要為大家詳細介紹了C++實現(xiàn)MyString的示例代碼,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • 詳解C語言中雙向循環(huán)鏈表的實現(xiàn)

    詳解C語言中雙向循環(huán)鏈表的實現(xiàn)

    雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數(shù)據(jù)結(jié)點中都有兩個指針,分別指向直接后繼和直接前驅(qū)。本文將用C語言實現(xiàn)雙向循環(huán)鏈表,需要的可以參考一下
    2022-06-06
  • OpenCV實現(xiàn)平均背景法

    OpenCV實現(xiàn)平均背景法

    這篇文章主要為大家詳細介紹了OpenCV實現(xiàn)平均背景法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • C++11中初始化列表initializer lists的使用方法

    C++11中初始化列表initializer lists的使用方法

    C++11引入了初始化列表來初始化變量和對象,自定義類型,如果想用初始化列表就要包含initializer_list頭文件
    2021-09-09
  • C++深入詳解單例模式與特殊類設(shè)計的實現(xiàn)

    C++深入詳解單例模式與特殊類設(shè)計的實現(xiàn)

    這篇文章主要為大家詳細介紹了C++單例模式和特殊類的設(shè)計,單例模式這種類型的設(shè)計模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-06-06
  • C++中sprintf使用的方法與printf的區(qū)別分析

    C++中sprintf使用的方法與printf的區(qū)別分析

    這篇文章主要介紹了C++中sprintf使用的方法與printf的區(qū)別,實例分析了sprintf與printf的具體用法及相關(guān)注意事項,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-01-01
  • 用C語言求解一元二次方程的簡單實現(xiàn)

    用C語言求解一元二次方程的簡單實現(xiàn)

    這篇文章主要介紹了用C語言求解一元二次方程的簡單實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C/C++實現(xiàn)線性順序表的示例代碼

    C/C++實現(xiàn)線性順序表的示例代碼

    使用順序存儲結(jié)構(gòu)的線性存儲結(jié)構(gòu)的表為線性順序表。本文將分別利用C語言和C++實現(xiàn)線性順序表,文中示例代碼講解詳細,需要的可以參考一下
    2022-05-05
  • C++中的stack容器和queue容器操作代碼

    C++中的stack容器和queue容器操作代碼

    C++中stack和queue容器介紹,stack是一種先進后出的數(shù)據(jù)結(jié)構(gòu),而queue是一種先進先出的數(shù)據(jù)結(jié)構(gòu),本文通過實例代碼介紹C++中的stack容器和queue容器,感興趣的朋友跟隨小編一起看看吧
    2025-11-11

最新評論

南投县| 韶关市| 兰考县| 博爱县| 昭平县| 烟台市| 尤溪县| 常德市| 会昌县| 鸡西市| 遂宁市| 夹江县| 易门县| 沂源县| 东明县| 凤阳县| 万荣县| 察雅县| 灵石县| 双桥区| 林口县| 张掖市| 新和县| 河间市| 淳化县| 宁乡县| 高青县| 内江市| 那曲县| 景德镇市| 托克逊县| 抚远县| 岐山县| 长顺县| 丹阳市| 深圳市| 秦皇岛市| 襄城县| 金门县| 新竹县| 华亭县|