重排序

一、重排序。

1、為什么需要重排序?

? ?現在的CPU一般采用流水線來執行指令。一個指令的執行被分成:取指、譯碼、訪存、執行、寫回、等若干個階段。然后,多條指令可以同時存在于流水線中,同時被執行。

指令流水線并不是串行的,并不會因為一個耗時很長的指令在“執行”階段呆很長時間,而導致后續的指令都卡在“執行”之前的階段上。我們編寫的程序都要經過優化后(編譯器和處理器會對我們的程序進行優化以提高運行效率)才會被運行,優化分為很多種,其中有一種優化叫做重排序,重排序需要遵守as-if-serial規則和happens-before規則,不能說你想怎么排就怎么排,如果那樣豈不是亂了套。重排序的目的是為了性能。

Example:
理想情況下:
過程A:cpu0—寫入1—> bank0;
過程B:cpu0—寫入2—> bank1;
如果bank0狀態為busy, 則A過程需要等待
如果進行重排序,則直接可以先執行B過程。

2、重排序分類。

在執行程序時,為了提高性能,編譯器和處理器會對指令做重排序。

  1. 編譯器優化重排序:編譯器在不改變單線程程序語義的前提下,可以重新安排語句的執行順序。
  2. 指令級并行的重排序:如果不存l在數據依賴性,處理器可以改變語句對應機器指令的執行順序。
  3. 內存系統的重排序:處理器使用緩存和讀寫緩沖區,這使得加載和存儲操作看上去可能是在亂序執行。

但是,可以通過插入特定類型的Memory Barrier來禁止特定類型的編譯器重排序和處理器重排序。

3、重排序過程。

一個好的內存模型實際上會放松對處理器和編譯器規則的束縛,也就是說軟件技術和硬件技術都為同一個目標而進行奮斗:在不改變程序執行結果的前提下,盡可能提高并行度。JMM對底層盡量減少約束,使其能夠發揮自身優勢。因此,在執行程序時,為了提高性能,編譯器和處理器常常會對指令進行重排序。一般重排序可以分為如下三種:

?
從源碼到最終執行的指令序列的示意圖
  1. 編譯器優化的重排序。編譯器在不改變單線程程序語義的前提下,可以重新安排語句的執行順序
  2. 指令級并行的重排序。現代處理器采用了指令級并行技術來將多條指令重疊執行。如果不存在數據依賴性,處理器可以改變語句對應機器指令的執行順序
  3. 內存系統的重排序。由于處理器使用緩存和讀/寫緩沖區,這使得加載和存儲操作看上去可能是在亂序執行的。

如圖,1屬于編譯器重排序,而2和3統稱為處理器重排序。這些重排序會導致線程安全的問題,一個很經典的例子就是DCL問題。針對編譯器重排序,JMM的編譯器重排序規則會禁止一些特定類型的編譯器重排序針對處理器重排序,編譯器在生成指令序列的時候會通過插入內存屏障指令來禁止某些特殊的處理器重排序

那么什么情況下,不能進行重排序了?下面就來說說數據依賴性。有如下代碼:

double pi = 3.14 //A

double r = 1.0 //B

double area = pi * r * r //C

這是一個計算圓面積的代碼,由于A,B之間沒有任何關系,對最終結果也不會存在關系,它們之間執行順序可以重排序。因此可以執行順序可以是A->B->C或者B->A->C執行最終結果都是3.14,即A和B之間沒有數據依賴性。具體的定義為:如果兩個操作訪問同一個變量,且這兩個操作有一個為寫操作,此時這兩個操作就存在數據依賴性這里就存在三種情況:1. 讀后寫;2.寫后寫;3. 寫后讀,者三種操作都是存在數據依賴性的,如果重排序會對最終執行結果會存在影響。編譯器和處理器在重排序時,會遵守數據依賴性,編譯器和處理器不會改變存在數據依賴性關系的兩個操作的執行順序。

4、重排序對多線程的影響。

class ReorderExample { int a = 0; boolean flag = false; public void writer() { a = 1; //1 flag = true; //2 } Public void reader() { if (flag) { //3 int i = a * a; //4 …… } } } 

flag為標志位,表示a有沒有被寫入,當A線程執行 writer 方法,B線程執行 reader 方法,線程B在執行4操作的時候,能否看到線程A對a的寫入操作?

答案是: 不一定!

由于操作1和操作2沒有數據依賴關系,編譯器和處理器可以對這兩個操作重排序。

如果操作1和操作2做了重排序,程序執行時,線程A首先寫標記變量 flag,隨后線程 B 讀這個變量。由于條件判斷為真,線程 B 將讀取變量a。此時,變量 a 還根本沒有被線程 A 寫入,在這里多線程程序的語義被重排序破壞了!

?

二、數據依賴性。

如果兩個操作訪問同一個變量,且這兩個操作中有一個為寫操作,此時這兩個操作之間就存在數據依賴性。數據依賴分下列三種類型:

名稱代碼示例說明
寫后讀a = 1;b = a;寫一個變量之后,再讀這個位置。
寫后寫a = 1;a = 2;寫一個變量之后,再寫這個變量。
讀后寫a = b;b = 1;讀一個變量之后,再寫這個變量。

上面三種情況,只要重排序兩個操作的執行順序,程序的執行結果將會被改變。前面提到過,編譯器和處理器可能會對操作做重排序。編譯器和處理器在重排序時,會遵守數據依賴性,編譯器和處理器不會改變存在數據依賴關系的兩個操作的執行順序。注意,這里所說的數據依賴性僅針對單個處理器中執行的指令序列和單個線程中執行的操作,不同處理器之間和不同線程之間的數據依賴性不被編譯器和處理器考慮如果兩個操作訪問同一個變量,且這兩個操作中有一個為寫操作,此時這兩個操作之間就存在數據依賴性。所以有數據依賴性的語句不能進行重排序。

三、as-if-serial規則。

as-if-serial語義的意思指:不管怎么重排序(編譯器和處理器為了提高并行度),(單線程)程序的執行結果不能被改變。編譯器,runtime 和處理器都必須遵守as-if-serial語義。

為了遵守as-if-serial語義,編譯器和處理器不會對存在數據依賴關系的操作做重排序,因為這種重排序會改變執行結果。但是,如果操作之間不存在數據依賴關系,這些操作可能被編譯器和處理器重排序。為了具體說明,請看下面計算圓面積的代碼示例:

double pi  = 3.14;    //A
double r   = 1.0;     //B
double area = pi * r * r; //C

上面三個操作的數據依賴關系如下圖所示:

如上圖所示,A和C之間存在數據依賴關系,同時B和C之間也存在數據依賴關系。因此在最終執行的指令序列中,C不能被重排序到A和B的前面(C排到A和B的前面,程序的結果將會被改變)。但A和B之間沒有數據依賴關系,編譯器和處理器可以重排序A和B之間的執行順序。as-if-serial語義把單線程程序保護了起來,遵守as-if-serial語義的編譯器,runtime 和處理器共同為編寫單線程程序的程序員創建了一個幻覺:單線程程序是按程序的順序來執行的as-if-serial語義使單線程程序員無需擔心重排序會干擾他們,也無需擔心內存可見性問題

四、happens-before規則。

?

具體的一共有六項規則:

1、程序順序規則。(可見性)

一個線程中的每個操作,happens-before于該線程中的任意后續操作。程序順序規則中所說的每個操作happens-before于該線程中的任意后續操作并不是說前一個操作必須要在后一個操作之前執行,而是指前一個操作的執行結果必須對后一個操作可見,如果不滿足這個要求那就不允許這兩個操作進行重排序。

2、監視器鎖規則。

對一個鎖的解鎖,happens-before于隨后對這個鎖的加鎖。

3、volatile變量規則。

對一個volatile域的寫,happens-before于任意后續對這個volatile域的讀。

4、傳遞性。

如果A happens-before B,且B happens-before C,那么A happens-before C。

5、start()規則。

如果線程A執行操作ThreadB.start()(啟動線程B),那么A線程的ThreadB.start()操作happens-before于線程B中的任意操作。

6、join()規則。

如果線程A執行操作ThreadB.join()并成功返回,那么線程B中的任意操作happens-before于線程A從ThreadB.join()操作成功返回。

7、程序中斷規則。

對線程interrupted()方法的調用先行于被中斷線程的代碼檢測到中斷時間的發生。

8、對象finalize規則。

一個對象的初始化完成(構造函數執行結束)先行于發生它的finalize()方法的開始。

?

?

轉載于:https://www.cnblogs.com/igoodful/p/9473253.html

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

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

相關文章

tableau三軸該怎么做_如何用tableau繪制城市地鐵線路圖?

在用tableau繪制地鐵線路圖之前,當然是要獲取相關的數據啦我們以鄭州目前已開通的地鐵為例,分別是1、2、5號線經度、維度可在 網頁上自行搜索哦(以谷歌地圖為準)有了這些下面我們就要開始啦將Excel中你所需要的數據直接導入到tabl…

JS七種加密解密方法

HTML或JS加密解密 本文一共介紹了七種方法:   一:最簡單的加密解密   二:轉義字符"\"的妙用   三:使用Microsoft出品的腳本編碼器Script Encoder來進行編碼 (自創簡單解碼)  …

提高solr的搜索速度

之前是使用12臺機分布式搜索,1臺為主機做索引并分發給子機,8臺做大索引搜索服務,3 臺做小索引搜索服務,配置基本是內存在4-8G,cpu:2-8core的服務器,索引的大小為8G。搜索的響應時間 是150ms左右。&#xff…

哲學到編程:思想的實例化

萬古長江水,千年儒釋道。歷史的長流中,蕓蕓眾生,參差不齊,但總是能夠總結出一個“生旦凈末丑”來。儒、釋、道,五千年的中華文化,卻總是圍繞著這三種主流思想交相演繹。千年間,豪士俊杰&#xf…

python 字符串交集_Python序列--集合(set)

集合集合用于保存不重復元素。- 集合和列表非常相似- 不同點:1.集合中只能存儲不可變對象2.集合中存儲的對象是無序(不是按照元素的插入順序保存)3.集合中不能出現重復的元素集合的所有元素都放在一對”{ }” 中,兩個相鄰的元素之間用”,”分隔。集合最好…

mysql binlog日志查看及解碼

mysql bin log日志導出 mysqlbinlog mysql-bin.000005 > /home/17bin.log 需要添加參數(--base64-outputdecode-rows -v)對輸出結果解碼 mysqlbinlog --base64-outputdecode-rows -v mysql-bin.000005 > /home/17bin.log轉載于:https://www.cnbl…

【Python開發】Python的GUI用法總結

引用模塊(tkinter): 1 from tkinter import * 主窗口設置: 1 # 主窗口 2 tk Tk() # 主窗口實例化 3 tk.title("文本處理工具") # 主窗口標題 4 tk.geometry("700x4001001…

JAVA 環境變量配置

JAVA 環境變量配置 1. 安裝JDK 2.配置系統變量 新建          JAVA_HOME:D:\Program Files\Java\jdk1.8.0_65 Path添加       %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin; 新建CLASSPATH  .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; 3.完成…

8修改host_正點原子【STM32-F407探索者】第五十九章 USB 鼠標鍵盤(Host)實驗

1)資料下載:點擊資料即可下載2)對正點原子Linux感興趣的同學可以加群討論:9354467413)關注正點原子公眾號,獲取最新資料更新上一章我們向大家介紹了如何利用 STM32F4 的 USB HOST 接口來驅動 U 盤,本章,我們 將利用 ST…

CF815C Karen and Supermarket [樹形DP]

題目傳送門 Karen and Supermarket On the way home, Karen decided to stop by the supermarket to buy some groceries. She needs to buy a lot of goods, but since she is a student her budget is still quite limited. In fact, she can only spend up to b dollars. Th…

linux命令積累之egrep命令

學搭建Nginx環境,必須要配置的Nginx.conf文件中,如下:#user nobody;worker_processes 1;#error_log logs/error.log;#error_log logs/error.log notice;#error_log logs/error.log info;#pid logs/nginx.pid;events { worke…

Sublime Text 3 安裝及插件推薦

本篇介紹跨平臺編輯器Sublime Text 3的安裝和其插件推薦。 目錄: 1.介紹 2.下載安裝 3.插件 4.參考資料 1.介紹 Sublime Text具有漂亮的用戶界面和強大的功能,例如代碼縮略圖,Python的插件,代碼段等。還可自定義鍵綁定&#xff0c…

6工程文件夾作用_data_dragon數據工程小工具收集

最近在GitHub上創建了一個新工程,收集個人在數據工程工作的小工具集合,命名為data_dragon (數據一條龍)。取這個名字的是希望這些腳本或代碼能夠復用,端到端地減少臨時數據處理的時間。最近因為工作上的一些變化,寫作節奏有點被打…

暑假第十七測

題解&#xff1a; 第一題 #include<bits/stdc.h> using namespace std; #define ll long long const int M 1e5 10; ll a[M], b[M], ans; priority_queue <ll, vector<ll> , greater<ll> > Q; int main(){freopen("buy.in","r",…

Uva 11354 LCA 倍增祖先

題目鏈接&#xff1a;https://vjudge.net/contest/144221#problem/B 題意&#xff1a;找一條從 s 到 t 的路&#xff0c;使得瓶頸路最小。 點的數目是10^4&#xff0c;如果向之前的方案求 maxcost數組&#xff0c;O(n*n)時間是過不了的&#xff0c;這個時候&#xff0c;用到了…

Nginx搭建flv視頻點播服務器

Nginx搭建flv視頻點播服務器前一段時間使用Nginx搭建的多媒體服務器只能在緩沖過的時間區域內拖放, 而不能拖放到未緩沖的地方. 這就帶來了一個問題: 如果視頻限速的速率很小, 那么客戶端觀看視頻時肯定不流暢, 而且用戶不能向前拖放, 用戶體驗很不好. 如果視頻限速的速率很大或…

編碼拾遺

1 #!/usr/bin/env python32 #-*- coding:utf-8 -*-3 4 Administrator 5 2018/8/16 6 7 8 # fopen("demo","r",encoding"utf8")9 # dataf.read() 10 # print(data) 11 # f.close() 12 13 14 # print("沈哲子") 15 16 s"中國&qu…

Xcode:Foundation框架找不到,或者是自動提示出現問題

問題描述&#xff1a;Foundation框架找不到&#xff0c;或者是自動提示出現問題 之前的操作&#xff1a;手賤&#xff0c;不少心把編譯器里面的源碼改了處理辦法&#xff1a;清理緩存緩存位置&#xff1a;點擊桌面后&#xff0c;選擇系統菜單欄&#xff1a;前往—電腦—硬盤—用…

mybatis 不生效 參數_Mybatis-日志配置

日志Mybatis 的內置日志工廠提供日志功能&#xff0c;內置日志工廠將日志交給以下其中一種工具作代理&#xff1a;SLF4JApache Commons LoggingLog4j 2Log4jJDK loggingMyBatis 內置日志工廠基于運行時自省機制選擇合適的日志工具。它會使用第一個查找得到的工具(按上文列舉的順…

PS通過濾色實現簡單的圖片拼合

素材如下&#xff1a; 素材一&#xff1a; 雪山 素材二&#xff1a; 月亮 效果&#xff1a; 實現步驟 1、在PS中打開雪山素材一 2、將月亮素材直接拖入雪山所在的圖層中 3、鎖定置入素材的高寬比&#xff08;點擊一下鏈狀按鈕&#xff09; 4、調整月亮到合適大小合適位置 5、…