Linux C/C++并發編程實戰(8)CAS機制的ABA問題

文章目錄

    • 無鎖隊列中的ABA問題
    • ABA問題解決方案

ABA問題:CAS在操作的時候會檢查變量的值是否被更改過,如果沒有則更新值,但是帶來一個問題,最開始的值是A,接著變成B,最后又變成了A。經過檢查這個值確實沒有修改過,因為最后的值還是A,但是實際上這個值確實已經被修改過了。

聽起來似乎沒有什么嚴重的問題,舉幾個實際的例子看下。

無鎖隊列中的ABA問題

/* Naive lock-free stack which suffers from ABA problem.*/
class Stack {std::atomic<Obj*> top_ptr;//// Pops the top object and returns a pointer to it.//Obj* Pop() {while (1) {Obj* ret_ptr = top_ptr;if (ret_ptr == nullptr) return nullptr;// For simplicity, suppose that we can ensure that this dereference is safe// (i.e., that no other thread has popped the stack in the meantime).Obj* next_ptr = ret_ptr->next;// If the top node is still ret, then assume no one has changed the stack.// (That statement is not always true because of the ABA problem)// Atomically replace top with next.if (top_ptr.compare_exchange_weak(ret_ptr, next_ptr)) {return ret_ptr;}// The stack has changed, start over.}}//// Pushes the object specified by obj_ptr to stack.//void Push(Obj* obj_ptr) {while (1) {Obj* next_ptr = top_ptr;obj_ptr->next = next_ptr;// If the top node is still next, then assume no one has changed the stack.// (That statement is not always true because of the ABA problem)// Atomically replace top with obj.if (top_ptr.compare_exchange_weak(next_ptr, obj_ptr)) {return;}// The stack has changed, start over.}}
};

考慮有兩個線程并發的訪問該隊列。

初始時,棧頂元素是 A,A 指向 B,B 指向 C。

top --> A --> B --> C
  • Thread 1 執行 pop 操作,將棧頂元素 A 彈出,取出了top_ptr, 和 next_ptr后被中斷。
Obj* ret_ptr = top_ptr;
if (ret_ptr == nullptr) return nullptr;// For simplicity, suppose that we can ensure that this dereference is safe// (i.e., that no other thread has popped the stack in the meantime).Obj* next_ptr = ret_ptr->next;

此刻,Thread 1里看到的是top_ptr等于A, next_ptr 等于B,問題其實就在這里了,保證top_ptr等于A時,并不能保證next_ptr等于B。

  • Thread 2 執行 pop 操作,將棧頂元素從 A 改為 B。
top --> B --> C
  • Thread 2 再次執行 pop 操作,將棧頂元素從 B 改為 C。
top --> C
  • Thread 2 執行 push 操作,將元素 A 推回到棧頂。
top --> A --> C
  • Thread 1 繼續執行,執行 compare_exchange_weak(A, B),由于 top == ret,操作成功,棧頂元素變為了 B。
    此刻
top --> B(already delete)
  • Thread 1 訪問棧頂元素,但是 B 已經被刪除,這導致了 ABA 問題。
當從列表中刪除一個項目并釋放其內存后,如果再次分配一個新項目并將其添加到列表中,由于最近最常使用(MRU)的內存分配策略,新分配的對象通常會位于被刪除對象的相同位置。
或者是在啟用緩存機制時,重新分配的對象也有極大的概率是之前釋放的對象。

ABA問題解決方案

在原有的內容上添加額外的“標簽”或“戳記”位。例如,使用比較和交換(compare and swap)操作指針的算法可以使用地址的低位來表示指針成功修改的次數。因此,即使地址相同,下一次比較和交換操作也會失敗,因為標簽位不匹配。這種情況有時被稱為ABA?,因為第二個A與第一個略有不同。這種帶標簽的狀態引用也被用于事務內存(transactional memory)中。

在實現中,可以使用帶標簽的指針來解決ABA問題,其中指針的低位用于存儲標簽信息。然而,如果支持雙寬比較和交換(double-width CAS),更常見的做法是使用單獨的標簽字段。

通過使用標簽位,每次對共享數據進行操作時都會更新標簽,即使地址相同,標簽的變化也能夠反映出對象的修改歷史。這樣,在進行比較和交換操作時,除了比較地址外,還需要比較標簽位,從而更可靠地檢測到對象的變化。

如果“標簽”字段發生了環繞(wraparound),那么對抗ABA問題的保證就不再有效。然而,根據觀察,在當前存在的CPU上,并且使用60位標簽,只要程序的生命周期(即在不重新啟動程序的情況下)限制在10年內,就不會發生環繞;此外,有人認為,為了實際目的,通常只需擁有40-48位的標簽來確保不會發生環繞。由于現代CPU(特別是所有現代x64 CPU)傾向于支持128位的CAS(比較和交換)操作,這可以提供對抗ABA問題的可靠保證。

當使用128位CAS操作時,除了存儲指針地址外,還可以存儲一個更大的標簽值。因為標簽位數更多,所以即使在長時間運行的程序中,標簽的環繞概率也非常低,幾乎可以忽略不計。

通過使用128位CAS操作,并保留足夠長度的標簽位,可以提供對抗ABA問題的堅實保證。這意味著在多線程或并發環境中,即使對象的地址沒有改變,只要標簽發生變化,CAS操作也會失敗,從而可以正確檢測到對象的變化。這種方法在實踐中被廣泛采用,以確保數據的一致性和并發操作的正確性。

所謂的版本號、標記基本都是采用這個原理。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/212503.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/212503.shtml
英文地址,請注明出處:http://en.pswp.cn/news/212503.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Leetcode每日一題

https://leetcode.cn/problems/binary-tree-preorder-traversal/ 這道題目需要我們自行進行創建一個數組&#xff0c;題目也給出我們需要自己malloc一個數組來存放&#xff0c;這樣能達到我們遍歷的效果&#xff0c;我們來看看他的接口函數給的是什么。 可以看到的是這個接口函…

說說webpack中常見的loader?解決了什么問題?

在Webpack中&#xff0c;Loader是用于處理各種文件類型的模塊加載器&#xff0c;它們用于對文件進行轉換、處理和加載。常見的Loader解決了以下問題&#xff1a; 處理 JavaScript 文件&#xff1a;Babel Loader用于將最新的JavaScript語法轉譯為瀏覽器兼容的版本&#xff0c;以…

5_CSS三大特性盒子模型

第5章-盒子模型【比屋教育】 本課目標&#xff08;Objective&#xff09; 掌握CSS三大特性理解什么是盒子模型掌握內邊距padding的用法掌握外邊距margin的用法 1. CSS的層疊&#xff0c;繼承&#xff0c;優先級 1.1 CSS層疊 層疊&#xff1a;是指多個CSS樣式疊加到同一個元…

Web(8)SQL注入

Web網站&#xff08;對外門戶&#xff09; 原理&#xff1a;not>and>or(優先級) 一.低級注入 order by的作用是對字段進行排序&#xff0c;如order by 5&#xff0c;根據第五個字段 進行排序&#xff0c;如果一共有4個字段&#xff0c;輸入order by 5系統就會報錯不 …

詳細介紹開源固件-TF-A

什么是TF-A&#xff1f; TF-A&#xff08;Trusted Firmware-A&#xff09;是一種用于嵌入式系統的開源固件&#xff0c;而不是Linux的一部分。TF-A主要用于ARM架構的處理器和設備&#xff0c;它提供了一組安全和可信任的軟件組件&#xff0c;用于引導和初始化系統。 如下是其…

GD32F30X-RT-Thread學習-線程管理

1. 軟硬件平臺 GD32F307E-START Board開發板MDK-ARM Keil 2.RT-Thread Nano 3.RT-Thread 內核學習-線程管理 ? 在多線程操作系統中&#xff0c;可以把一個復雜的應用分解成多個小的、可調度的、序列化的程序單元&#xff0c;當合理地劃分任務并正確地執行時&#xff0c;這…

qt可以詳細寫的項目或技術

1.QT 圖形視圖框架 2.QT 模型視圖結構 3.QT列表顯示大量信息 4.QT播放器 5.QT 編解碼 6.QT opencv

Linux--RedHat--安裝和配置C++環境

百度下載&#xff0c;安裝包&#xff1a; 鏈接&#xff1a;https://pan.baidu.com/s/1IgBfCCRxGYZ_PPiedad0xQ 提取碼&#xff1a;ffff 下載后&#xff0c;建個目錄&#xff0c;先解壓好安裝包&#xff01; &#xff08;兩種方法&#xff09;執行如下命令&#xff1a; 參考…

Bypass open_basedir

講解 open_basedir是php.ini中的一個配置選項&#xff0c;可用于將用戶訪問文件的活動范圍限制在指定的區域。 假設open_basedir/var/www/html/web1/:/tmp/&#xff0c;那么通過web1訪問服務器的用戶就無法獲取服務器上除了/var/www/html/web1/和/tmp/這兩個目錄以外的文件。…

Java——面試:String 和 StringBuffer 的區別?

相同點&#xff1a; String 和 StringBuffer&#xff0c;它們可以儲存和操作字符串&#xff0c; 即包含多個字符的字符數據。 String 和 StringBuffer 的區別有以下幾點&#xff1a; 1.String 類提供了數值不可改變的字符串。而 StringBuffer 類提供的字符串進行修改。 當你知…

洛谷 P8674 [藍橋杯 2018 國 B] 調手表

文章目錄 [藍橋杯 2018 國 B] 調手表題目描述輸入格式輸出格式樣例 #1樣例輸入 #1樣例輸出 #1 提示 題意解析CODE分析一下復雜度 [藍橋杯 2018 國 B] 調手表 題目描述 小明買了塊高端大氣上檔次的電子手表&#xff0c;他正準備調時間呢。 在 M78 星云&#xff0c;時間的計量…

JVM虛擬機:命令行查看JVM垃圾回收器的執行信息

在eclipse中打開命令行窗口 window->show view->Terminal 這樣就打開了Terminal窗口&#xff0c;效果如下所示&#xff1a; java -XX:PrintCommandLineFlags -version 這個命令可以查看一些配置信息&#xff0c;其中最重要的配置信息就是&#xff0c;當前使用的G1回收器…

什么是漏洞掃描

漏洞掃描是指基于漏洞數據庫&#xff0c;通過掃描等手段對指定的遠程或者本地計算機系統的安全脆弱性進行檢測&#xff0c;發現可利用漏洞的一種安全檢測的 行為&#xff0c;也是一類重要的網絡安全技術。它和防火墻、入侵檢測系統互相配合&#xff0c;能夠有效提高網絡的安全性…

鍵盤打字盲打練習系列之成為大師——5

一.歡迎來到我的酒館 盲打&#xff0c;成為大師&#xff01; 目錄 一.歡迎來到我的酒館二.關于盲打你需要知道三.值得收藏的練習打字網站 二.關于盲打你需要知道 盲打系列教程&#xff0c;終于寫到終章了。。。一開始在看網上視頻&#xff0c;看到up主熟練的打字技巧&#xff…

LabVIEW與Tektronix示波器實現電源測試自動化

LabVIEW與Tektronix示波器實現電源測試自動化 在現代電子測試與測量領域&#xff0c;自動化測試系統的構建是提高效率和精確度的關鍵。本案例介紹了如何利用LabVIEW軟件結合Tektronix MDO MSO DPO2000/3000/4000系列示波器&#xff0c;開發一個自動化測試項目。該項目旨在自動…

javascript中Reflect是什么?三分鐘初識

目錄 1. Reflect是什么&#xff1f;2. 為什么會出現Reflect&#xff1f;3. 需要怎么去使用Reflect&#xff1f;4. 最終的結果解決什么&#xff1f;5. 使用的注意點6. 常用的技巧 Reflect是Javascript中的一個內置對象&#xff0c;它提供了一組用于操作對象的方法&#xff0c;可…

Spring - BeanFactory和FactoryBean的理解

BeanFactory是什么&#xff1f; BeanFactory是Spring 容器的根接口&#xff0c;它是IOC的基本容器&#xff0c;負責管理和加載Bean&#xff0c;它為具體的IOC容器提供了最基本的規范&#xff0c;比如DefaultListableBeanFactory和ConfigurableBeanFactory&#xff0c;BeanFact…

《C++新經典設計模式》之第17章 中介者模式

《C新經典設計模式》之第17章 中介者模式 中介者模式.cpp 中介者模式.cpp #include <iostream> #include <map> #include <memory> using namespace std;// 中介者封裝一系列的對象交互 // 4種角色 // Mediator&#xff08;抽象中介者類&#xff09;&#x…

MYSQL練題筆記-高級查詢和連接-指定日期的產品價格

這依舊是中等題&#xff0c;想了好久&#xff0c;終于理解了很開心&#xff01; 一、題目相關內容 1&#xff09;相關的表和題目 2&#xff09;幫助理解題目的示例&#xff0c;提供返回結果的格式 二、自己初步的理解 題目是找出2019-08-16 時全部產品的價格&#xff0c;所以…

數字化時代的到來,IT運維產業正在發生深刻的變革

IT運維產業是隨著信息技術的發展而產生的&#xff0c;它涵蓋了從硬件到軟件、從應用到數據、從終端到云端等各個方面的維護和管理。隨著數字化時代的到來&#xff0c;IT運維產業正在發生深刻的變革。其中&#xff0c;大數據技術的廣泛應用和數據資源的日益豐富&#xff0c;正在…