聊聊併發(5):原子操作的實現原理
1 引言
原子(atom)本意是“不能被進一步分割的最小粒子”,而原子操作(atomic operation)意為”不可被中斷的一個或一系列操作” 。在多處理器上實現原子操作就變得有點複雜。本文讓我們一起來聊一聊在Inter處理器和Java裡是如何實現原子操作的。
2 術語定義
術語名稱 | 英文 | 解釋 |
快取行 | Cache line | 快取的最小操作單位 |
比較並交換 | Compare and Swap |
CAS操作需要輸入兩個數值,一箇舊值(期望操作前的值)和一個新值,在操作期間先比較下在舊值有沒有發生變化,如果沒有發生變化,才交換 |
CPU流水線 | CPU pipeline | CPU流水線的工作方式就象工業生產上的裝配流水線,在CPU中由5~6個不同功能的電路單元組成一條指令處理流水線,然後將一條X86指令分成5~6步後再由這些電路單元分別執行,這樣就能實現在一個CPU時鐘週期完成一條指令,因此提高CPU的運算速度。 |
記憶體順序衝突 | Memory order violation | 記憶體順序衝突一般是由假共享引起,假共享是指多個CPU同時修改同一個快取行的不同部分而引起其中一個CPU的操作無效,當出現這個記憶體順序衝突時,CPU必須清空流水線。 |
3 處理器如何實現原子操作
32位IA-32處理器使用基於對快取加鎖或匯流排加鎖的方式來實現多處理器之間的原子操作。
3.1 處理器自動保證基本記憶體操作的原子性
首先處理器會自動保證基本的記憶體操作的原子性。處理器保證從系統記憶體當中讀取或者寫入一個位元組是原子的,意思是當一個處理器讀取一個位元組時,其他處理器不能訪問這個位元組的記憶體地址。奔騰6和最新的處理器能自動保證單處理器對同一個快取行裡進行16/32/64位的操作是原子的,但是複雜的記憶體操作處理器不能自動保證其原子性,比如跨匯流排寬度,跨多個快取行,跨頁表的訪問。但是處理器提供匯流排鎖定和快取鎖定兩個機制來保證複雜記憶體操作的原子性。
3.2 使用匯流排鎖保證原子性
第一個機制是通過匯流排鎖保證原子性。如果多個處理器同時對共享變數進行讀改寫(i++就是經典的讀改寫操作)操作,那麼共享變數就會被多個處理器同時進行操作,這樣讀改寫操作就不是原子的,操作完之後共享變數的值會和期望的不一致,舉個例子:如果i=1,我們進行兩次i++操作,我們期望的結果是3,但是有可能結果是2。如下圖
原因是有可能多個處理器同時從各自的快取中讀取變數i,分別進行加一操作,然後分別寫入系統記憶體當中。那麼想要保證讀改寫共享變數的操作是原子的,就必須保證CPU1讀改寫共享變數的時候,CPU2不能操作快取了該共享變數記憶體地址的快取。
處理器使用匯流排鎖就是來解決這個問題的。所謂匯流排鎖就是使用處理器提供的一個LOCK#訊號,當一個處理器在總線上輸出此訊號時,其他處理器的請求將被阻塞住,那麼該處理器可以獨佔使用共享記憶體。
3.3 使用快取鎖保證原子性
第二個機制是通過快取鎖定保證原子性。在同一時刻我們只需保證對某個記憶體地址的操作是原子性即可,但匯流排鎖定把CPU和記憶體之間通訊鎖住了,這使得鎖定期間,其他處理器不能操作其他記憶體地址的資料,所以匯流排鎖定的開銷比較大,最近的處理器在某些場合下使用快取鎖定代替匯流排鎖定來進行優化。
頻繁使用的記憶體會快取在處理器的L1,L2和L3快取記憶體裡,那麼原子操作就可以直接在處理器內部快取中進行,並不需要宣告匯流排鎖,在奔騰6和最近的處理器中可以使用“快取鎖定”的方式來實現複雜的原子性。所謂“快取鎖定”就是如果快取在處理器快取行中記憶體區域在LOCK操作期間被鎖定,當它執行鎖操作回寫記憶體時,處理器不在總線上聲言LOCK#訊號,而是修改內部的記憶體地址,並允許它的快取一致性機制來保證操作的原子性,因為快取一致性機制會阻止同時修改被兩個以上處理器快取的記憶體區域資料,當其他處理器回寫已被鎖定的快取行的資料時會起快取行無效,在例1中,當CPU1修改快取行中的i時使用快取鎖定,那麼CPU2就不能同時快取了i的快取行。
但是有兩種情況下處理器不會使用快取鎖定。第一種情況是:當操作的資料不能被快取在處理器內部,或操作的資料跨多個快取行(cache line),則處理器會呼叫匯流排鎖定。第二種情況是:有些處理器不支援快取鎖定。對於Inter486和奔騰處理器,就算鎖定的記憶體區域在處理器的快取行中也會呼叫匯流排鎖定。
以上兩個機制我們可以通過Inter處理器提供了很多LOCK字首的指令來實現。比如位測試和修改指令BTS,BTR,BTC,交換指令XADD,CMPXCHG和其他一些運算元和邏輯指令,比如ADD(加),OR(或)等,被這些指令操作的記憶體區域就會加鎖,導致其他處理器不能同時訪問它。
4 JAVA如何實現原子操作
在java中可以通過鎖和迴圈CAS的方式來實現原子操作。
4.1 使用迴圈CAS實現原子操作
JVM中的CAS操作正是利用了上一節中提到的處理器提供的CMPXCHG指令實現的。自旋CAS實現的基本思路就是迴圈進行CAS操作直到成功為止,以下程式碼實現了一個基於CAS執行緒安全的計數器方法safeCount和一個非執行緒安全的計數器count。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
相關推薦聊聊併發(5):原子操作的實現原理1 引言 原子(atom)本意是“不能被進一步分割的最小粒子”,而原子操作(atomic operation)意為”不可被中斷的一個或一系列操作” 。在多處理器上實現原子操作就變得有點複雜。本文讓我們一起來聊一聊在Inter處理器和Java裡是如何實現原子操作的。 2 術語 Java併發(四):volatile的實現原理 Java併發(一):Java記憶體模型乾貨總結synchronized是一個重量級的鎖,volatile通常被比喻成輕量級的synchronized volatile是一個變數修飾符,只能用來修飾變數。 volatile寫:當寫一個volatile變數時,JMM會把該執行緒對應的本地記憶體中的共享變數重新整理到主記憶體。 volatile讀:當讀一 Java併發(七):雙重檢驗鎖定DCL Java併發(六):volatile的實現原理雙重檢查鎖定(Double Check Lock,DCL) 1、懶漢式單例模式,無法保證執行緒安全: public class Singleton { private static Singleton singleton; private Singleton Java併發(四):volatile的實現原理synchronized是一個重量級的鎖,volatile通常被比喻成輕量級的synchronized volatile是一個變數修飾符,只能用來修飾變數。 volatile寫:當寫一個volatile變數時,JMM會把該執行緒對應的本地記憶體中的共享變數重新整理到主記憶體。 volatile讀:當讀一個vo Gradle基本使用(5):檔案操作檔案集合的遍歷 1 collection.each {File file -> 2 println file.name 3 } 檔案集合可以進行合併、排除等集合操作,如下: 1FileCollection collection SpringBoot 2.x 學習筆記(5):ECharts+AJAX實現非同步資料載入1、JavaBean package cn.hadron.eba.bean; import java.io.Serializable; public class UserBean implements Serializable{ private String usernam Java並發(四):volatile的實現原理ont style tile 讀寫 flush microsoft div 圖片 println synchronized是一個重量級的鎖,volatile通常被比喻成輕量級的synchronized volatile是一個變量修飾符,只能用來修飾變量。 volatile寫 MVC之前的那點事兒系列(7):WebActivator的實現原理詳解文章內容 上篇文章,我們分析如何動態註冊HttpModule的實現,本篇我們來分析一下通過上篇程式碼原理實現的WebActivator類庫,WebActivator提供了3種功能,允許我們分別在HttpApplication初始化之前,之後以及ShutDown的時候分別執行指定的程式碼,示例如下: [ 聊聊併發(五)原子操作的實現原理1 引言 原子(atom)本意是“不能被進一步分割的最小粒子”,而原子操作(atomic operation)意為”不可被中斷的一個或一系列操作” 。在多處理器上實現原子操作就變得有點複雜。本文讓我們一起來聊一聊在Inter處理器和Java裡是如何實現原子操作的。 2 術語定義 arcgis jsapi介面入門系列(5):幾何(點線面)基本操作點 point: function () { //通過wkt生成點 //wkt,代表點的座標 let wkt = "POINT(113.566806 22.22445)"; git操作總結(5):遠端倉庫1.連結本地庫和遠端倉庫 git remote add origin [email protected]:michaelliao/learngit.git 2.推送到遠端 git push -u origin testbranch 3.建立遠端分支 git 小白學 Python 資料分析(5):Pandas (四)基礎操作(1)檢視資料在家為國家做貢獻太無聊,不如跟我一起學點 Python 人生苦短,我用 Python 前文傳送門: 小白學 Python 資料分析(1):資料分析基礎 小白學 Python 資料分析(2):Pandas (一)概述 小白學 Python 資料分析(3):Pandas (二)資料結構 Series C++傳智筆記(5):C++完整demo內部 urn else clas spa char log getx system MyPoint.h #pragma once class MyPoint { private: double x0, y0; //點坐標 public: void setPoint(d Windows Phone開發(5):室內裝修表示 index can 進行 解釋 技術 面板 啟動 垂直 為什麽叫室內裝修呢?呵呵,其實說的是布局,具體些嘛,就是在一個頁面中,你如何去擺放你的控件,如何管理它們,你說,像不像我們剛搬進新住所,要“裝修”一番?買一套什麽樣的茶幾和杯具(我說的“杯具”指的是原意,不要理解 Swift學習筆記(5):集合類型nbsp roc 三種 一個 刪除指定元素 edge 空值 port 自定義 目錄: 數組:Array 集合:Set 字典:Dictionary Swift提供Array(有序集合數據)、Set(無序無重復集合)和Dictionary(無序鍵值對集合)三 WAS集群系列(5):集群搭建:步驟3:安裝IHS軟件line col jsb eight none data 相關 blog mil 選擇“安裝IBM HTTPServer”選項,點擊“安裝向導”。例如以下圖提示: 安裝提示,逐步點擊“下一步”,當中偶有幾處細節註意就可以。列舉例如以下: (1)、產品安裝路徑與先 使用bottle進行web開發(5):Generating Content方便 () strings 系統 end byte 導致 res 名稱 在純粹的 WSGI中,你的應用能返回的數據類型是十分有限的,你必須返回可叠代的字符串,你能返回字符串是因為字符串是可以叠代的,但是這導致服務器將你的內容按一字符一字符的傳送,這個時候,Unicode 字 springCloud(5):Eureka的元數據與Eureka Server的rest端點springcloud eureka的元數據 eureka server的rest端點 一、Eureka的元數據1.1、簡介Eureka的元數據有兩種:標準元數據和自定義元數據。標準元數據指的是主機名、IP地址、端口號、狀態頁和健康檢查等信息,這些信息都會被發布在服務註冊表中,用於服務之間的調用。 python基礎(5):數字和字符串類型digi 數字 身高 isalnum 下標 spl 大小寫 () ljust 今天總結一下數據類型中的數字和字符串型。 預習: # 寫代碼,有如下變量,請按照要求實現每個功能 (共6分,每小題各0.5分) name = " aleX" # 1) 移除 name 變 轉每天一個linux命令(5):rm 命令每天 幫助信息 rbo 總計 com 刪除 強行 高度 linux中 昨天學習了創建文件和目錄的命令mkdir ,今天學習一下linux中刪除文件和目錄的命令: rm命令。rm是常用的命令,該命令的功能為刪除一個目錄中的一個或多個文件或目錄,它也可以將某個目錄及其下的所有文 |