當前位置:首頁 » 編程軟體 » 編譯器對多核

編譯器對多核

發布時間: 2022-12-11 05:53:21

⑴ C語言中的MPI編程和多線程有什麼區別,MPI編程中針對的是一台電腦多核還是多台電腦謝謝!

MPI(MPI是一個標准,有不同的具體實現,比如MPICH等)是多主機聯網協作進行並行計算的工具,當然也可以用於單主機上多核/多CPU的並行計算,不過效率低。它能協調多台主機間的並行計算,因此並行規模上的可伸縮性很強,能在從個人電腦到世界TOP10的超級計算機上使用。缺點是使用進程間通信的方式協調並行計算,這導致並行效率較低、內存開銷大、不直觀、編程麻煩。OpenMP是針對單主機上多核/多CPU並行計算而設計的工具,換句話說,OpenMP更適合單台計算機共享內存結構上的並行計算。由於使用線程間共享內存的方式協調並行計算,它在多核/多CPU結構上的效率很高、內存開銷小、編程語句簡潔直觀,因此編程容易、編譯器實現也容易(現在最新版的C、C++、Fortran編譯器基本上都內置OpenMP支持)。不過OpenMP最大的缺點是只能在單台主機上工作,不能用於多台主機間的並行計算!如果要多主機聯網使用OpenMP(比如在超級計算機上),那必須有額外的工具幫助,比如MPI+OpenMP混合編程。或者是將多主機虛擬成一個共享內存環境(Intel有這樣的平台),但這么做效率還不如混合編程,唯一的好處是編程人員可以不必額外學習MPI編程。

⑵ 多核處理器中的「核」指的是甚麼

所謂多核處理器,簡單說就是在一塊CPU基板上集成多個處理器核心,通過並行匯流排將各處理器核心連接起來的,工作速度快

java內存模型的JMM簡介

1)JSR133:
在Java語言規范裡面指出了JMM是一個比較開拓性的嘗試,這種嘗試視圖定義一個一致的、跨平台的內存模型,但是它有一些比較細微而且很重要的缺點。其實Java語言裡面比較容易混淆的關鍵字主要是synchronized和volatile,也因為這樣在開發過程中往往開發者會忽略掉這些規則,這也使得編寫同步代碼比較困難。
JSR133本身的目的是為了修復原本JMM的一些缺陷而提出的,其本身的制定目標有以下幾個: 保留目JVM的安全保證,以進行類型的安全檢查: 提供(out-of-thin-air safety)無中生有安全性,這樣「正確同步的」應該被正式而且直觀地定義 程序員要有信心開發多線程程序,當然沒有其他辦法使得並發程序變得很容易開發,但是該規范的發布主要目標是為了減輕程序員理解內存模型中的一些細節負擔 提供大范圍的流行硬體體系結構上的高性能JVM實現,現在的處理器在它們的內存模型上有著很大的不同,JMM應該能夠適合於實際的盡可能多的體系結構而不以性能為代價,這也是Java跨平台型設計的基礎 提供一個同步的習慣用法,以允許發布一個對象使他不用同步就可見,這種情況又稱為初始化安全(initialization safety)的新的安全保證 對現有代碼應該只有最小限度的影響 2)同步、非同步【這里僅僅指概念上的理解,不牽涉到計算機底層基礎的一些操作】:
在系統開發過程,經常會遇到這幾個基本概念,不論是網路通訊、對象之間的消息通訊還是Web開發人員常用的Http請求都會遇到這樣幾個概念,經常有人提到Ajax是非同步通訊方式,那麼究竟怎樣的方式是這樣的概念描述呢?
同步:同步就是在發出一個功能調用的時候,在沒有得到響應之前,該調用就不返回,按照這樣的定義,其實大部分程序的執行都是同步調用的,一般情況下,在描述同步和非同步操作的時候,主要是指代需要其他部件協作處理或者需要協作響應的一些任務處理。比如有一個線程A,在A執行的過程中,可能需要B提供一些相關的執行數據,當然觸發B響應的就是A向B發送一個請求或者說對B進行一個調用操作,如果A在執行該操作的時候是同步的方式,那麼A就會停留在這個位置等待B給一個響應消息,在B沒有任何響應消息回來的時候,A不能做其他事情,只能等待,那麼這樣的情況,A的操作就是一個同步的簡單說明。
非同步:非同步就是在發出一個功能調用的時候,不需要等待響應,繼續進行它該做的事情,一旦得到響應了過後給予一定的處理,但是不影響正常的處理過程的一種方式。比如有一個線程A,在A執行的過程中,同樣需要B提供一些相關數據或者操作,當A向B發送一個請求或者對B進行調用操作過後,A不需要繼續等待,而是執行A自己應該做的事情,一旦B有了響應過後會通知A,A接受到該非同步請求的響應的時候會進行相關的處理,這種情況下A的操作就是一個簡單的非同步操作。
3)可見性、可排序性
Java內存模型的兩個關鍵概念:可見性(Visibility)和可排序性(Ordering)
開發過多線程程序的程序員都明白,synchronized關鍵字強制實施一個線程之間的互斥鎖(相互排斥),該互斥鎖防止每次有多個線程進入一個給定監控器所保護的同步語句塊,也就是說在該情況下,執行程序代碼所獨有的某些內存是獨占模式,其他的線程是不能針對它執行過程所獨占的內存進行訪問的,這種情況稱為該內存不可見。但是在該模型的同步模式中,還有另外一個方面:JMM中指出了,JVM在處理該強制實施的時候可以提供一些內存的可見規則,在該規則裡面,它確保當存在一個同步塊時,緩存被更新,當輸入一個同步塊時,緩存失效。因此在JVM內部提供給定監控器保護的同步塊之中,一個線程所寫入的值對於其餘所有的執行由同一個監控器保護的同步塊線程來說是可見的,這就是一個簡單的可見性的描述。這種機器保證編譯器不會把指令從一個同步塊的內部移到外部,雖然有時候它會把指令由外部移動到內部。JMM在預設情況下不做這樣的保證——只要有多個線程訪問相同變數時必須使用同步。簡單總結:
可見性就是在多核或者多線程運行過程中內存的一種共享模式,在JMM模型裡面,通過並發線程修改變數值的時候,必須將線程變數同步回主存過後,其他線程才可能訪問到。
可排序性提供了內存內部的訪問順序,在不同的程序針對不同的內存塊進行訪問的時候,其訪問不是無序的,比如有一個內存塊,A和B需要訪問的時候,JMM會提供一定的內存分配策略有序地分配它們使用的內存,而在內存的調用過程也會變得有序地進行,內存的折中性質可以簡單理解為有序性。而在Java多線程程序裡面,JMM通過Java關鍵字volatile來保證內存的有序訪問。 1)簡單分析:
Java語言規范中提到過,JVM中存在一個主存區(Main Memory或Java Heap Memory),Java中所有變數都是存在主存中的,對於所有線程進行共享,而每個線程又存在自己的工作內存(Working Memory),工作內存中保存的是主存中某些變數的拷貝,線程對所有變數的操作並非發生在主存區,而是發生在工作內存中,而線程之間是不能直接相互訪問,變數在程序中的傳遞,是依賴主存來完成的。而在多核處理器下,大部分數據存儲在高速緩存中,如果高速緩存不經過內存的時候,也是不可見的一種表現。在Java程序中,內存本身是比較昂貴的資源,其實不僅僅針對Java應用程序,對操作系統本身而言內存也屬於昂貴資源,Java程序在性能開銷過程中有幾個比較典型的可控制的來源。synchronized和volatile關鍵字提供的內存中模型的可見性保證程序使用一個特殊的、存儲關卡(memory barrier)的指令,來刷新緩存,使緩存無效,刷新硬體的寫緩存並且延遲執行的傳遞過程,無疑該機制會對Java程序的性能產生一定的影響。
JMM的最初目的,就是為了能夠支持多線程程序設計的,每個線程可以認為是和其他線程不同的CPU上運行,或者對於多處理器的機器而言,該模型需要實現的就是使得每一個線程就像運行在不同的機器、不同的CPU或者本身就不同的線程上一樣,這種情況實際上在項目開發中是常見的。對於CPU本身而言,不能直接訪問其他CPU的寄存器,模型必須通過某種定義規則來使得線程和線程在工作內存中進行相互調用而實現CPU本身對其他CPU、或者說線程對其他線程的內存中資源的訪問,而表現這種規則的運行環境一般為運行該程序的運行宿主環境(操作系統、伺服器、分布式系統等),而程序本身表現就依賴於編寫該程序的語言特性,這里也就是說用Java編寫的應用程序在內存管理中的實現就是遵循其部分原則,也就是前邊提及到的JMM定義了Java語言針對內存的一些的相關規則。然而,雖然設計之初是為了能夠更好支持多線程,但是該模型的應用和實現當然不局限於多處理器,而在JVM編譯器編譯Java編寫的程序的時候以及運行期執行該程序的時候,對於單CPU的系統而言,這種規則也是有效的,這就是是上邊提到的線程和線程之間的內存策略。JMM本身在描述過程沒有提過具體的內存地址以及在實現該策略中的實現方法是由JVM的哪一個環節(編譯器、處理器、緩存控制器、其他)提供的機制來實現的,甚至針對一個開發非常熟悉的程序員,也不一定能夠了解它內部對於類、對象、方法以及相關內容的一些具體可見的物理結構。相反,JMM定義了一個線程與主存之間的抽象關系,其實從上邊的圖可以知道,每一個線程可以抽象成為一個工作內存(抽象的高速緩存和寄存器),其中存儲了Java的一些值,該模型保證了Java裡面的屬性、方法、欄位存在一定的數學特性,按照該特性,該模型存儲了對應的一些內容,並且針對這些內容進行了一定的序列化以及存儲排序操作,這樣使得Java對象在工作內存裡面被JVM順利調用,(當然這是比較抽象的一種解釋)既然如此,大多數JMM的規則在實現的時候,必須使得主存和工作內存之間的通信能夠得以保證,而且不能違反內存模型本身的結構,這是語言在設計之處必須考慮到的針對內存的一種設計方法。這里需要知道的一點是,這一切的操作在Java語言裡面都是依靠Java語言自身來操作的,因為Java針對開發人員而言,內存的管理在不需要手動操作的情況下本身存在內存的管理策略,這也是Java自己進行內存管理的一種優勢。
[1]原子性(Atomicity):
這一點說明了該模型定義的規則針對原子級別的內容存在獨立的影響,對於模型設計最初,這些規則需要說明的僅僅是最簡單的讀取和存儲單元寫入的的一些操作,這種原子級別的包括——實例、靜態變數、數組元素,只是在該規則中不包括方法中的局部變數。
[2]可見性(Visibility):
在該規則的約束下,定義了一個線程在哪種情況下可以訪問另外一個線程或者影響另外一個線程,從JVM的操作上講包括了從另外一個線程的可見區域讀取相關數據以及將數據寫入到另外一個線程內。
[3]可排序性(Ordering):
該規則將會約束任何一個違背了規則調用的線程在操作過程中的一些順序,排序問題主要圍繞了讀取、寫入和賦值語句有關的序列。
如果在該模型內部使用了一致的同步性的時候,這些屬性中的每一個屬性都遵循比較簡單的原則:和所有同步的內存塊一樣,每個同步塊之內的任何變化都具備了原子性以及可見性,和其他同步方法以及同步塊遵循同樣一致的原則,而且在這樣的一個模型內,每個同步塊不能使用同一個鎖,在整個程序的調用過程是按照編寫的程序指定指令運行的。即使某一個同步塊內的處理可能會失效,但是該問題不會影響到其他線程的同步問題,也不會引起連環失效。簡單講:當程序運行的時候使用了一致的同步性的時候,每個同步塊有一個獨立的空間以及獨立的同步控制器和鎖機制,然後對外按照JVM的執行指令進行數據的讀寫操作。這種情況使得使用內存的過程變得非常嚴謹!
如果不使用同步或者說使用同步不一致(這里可以理解為非同步,但不一定是非同步操作),該程序執行的答案就會變得極其復雜。而且在這樣的情況下,該內存模型處理的結果比起大多數程序員所期望的結果而言就變得十分脆弱,甚至比起JVM提供的實現都脆弱很多。因為這樣所以出現了Java針對該內存操作的最簡單的語言規范來進行一定的習慣限制,排除該情況發生的做法在於:
JVM線程必須依靠自身來維持對象的可見性以及對象自身應該提供相對應的操作而實現整個內存操作的三個特性,而不是僅僅依靠特定的修改對象狀態的線程來完成如此復雜的一個流程。
[4]三個特性的解析(針對JMM內部):
原子性(Atomicity):
訪問存儲單元內的任何類型的欄位的值以及對其更新操作的時候,除開long類型和double類型,其他類型的欄位是必須要保證其原子性的,這些欄位也包括為對象服務的引用。此外,該原子性規則擴展可以延伸到基於long和double的另外兩種類型:volatile long和volatile double(volatile為java關鍵字),沒有被volatile聲明的long類型以及double類型的欄位值雖然不保證其JMM中的原子性,但是是被允許的。針對non-long/non-double的欄位在表達式中使用的時候,JMM的原子性有這樣一種規則:如果你獲得或者初始化該值或某一些值的時候,這些值是由其他線程寫入,而且不是從兩個或者多個線程產生的數據在同一時間戳混合寫入的時候,該欄位的原子性在JVM內部是必須得到保證的。也就是說JMM在定義JVM原子性的時候,只要在該規則不違反的條件下,JVM本身不去理睬該數據的值是來自於什麼線程,因為這樣使得Java語言在並行運算的設計的過程中針對多線程的原子性設計變得極其簡單,而且即使開發人員沒有考慮到最終的程序也沒有太大的影響。再次解釋一下:這里的原子性指的是原子級別的操作,比如最小的一塊內存的讀寫操作,可以理解為Java語言最終編譯過後最接近內存的最底層的操作單元,這種讀寫操作的數據單元不是變數的值,而是本機碼,也就是前邊在講《Java基礎知識》中提到的由運行器解釋的時候生成的Native Code。
可見性(Visibility):
當一個線程需要修改另外線程的可見單元的時候必須遵循以下原則: 一個寫入線程釋放的同步鎖和緊隨其後進行讀取的讀線程的同步鎖是同一個從本質上講,釋放鎖操作強迫它的隸屬線程【釋放鎖的線程】從工作內存中的寫入緩存裡面刷新(專業上講這里不應該是刷新,可以理解為提供)數據(flush操作),然後獲取鎖操作使得另外一個線程【獲得鎖的線程】直接讀取前一個線程可訪問域(也就是可見區域)的欄位的值。因為該鎖內部提供了一個同步方法或者同步塊,該同步內容具有線程排他性,這樣就使得上邊兩個操作只能針對單一線程在同步內容內部進行操作,這樣就使得所有操作該內容的單一線程具有該同步內容(加鎖的同步方法或者同步塊)內的線程排他性,這種情況的交替也可以理解為具有「短暫記憶效應」。這里需要理解的是同步的雙重含義:使用鎖機制允許基於高層同步協議進行處理操作,這是最基本的同步;同時系統內存(很多時候這里是指基於機器指令的底層存儲關卡memory barrier,前邊提到過)在處理同步的時候能夠跨線程操作,使得線程和線程之間的數據是同步的。這樣的機制也折射出一點,並行編程相對於順序編程而言,更加類似於分布式編程。後一種同步可以作為JMM機制中的方法在一個線程中運行的效果展示,注意這里不是多個線程運行的效果展示,因為它反應了該線程願意發送或者接受的雙重操作,並且使得它自己的可見區域可以提供給其他線程運行或者更新,從這個角度來看,使用鎖和消息傳遞可以視為相互之間的變數同步,因為相對其他線程而言,它的操作針對其他線程也是對等的。 一旦某個欄位被申明為volatile,在任何一個寫入線程在工作內存中刷新緩存的之前需要進行進一步的內存操作,也就是說針對這樣的欄位進行立即刷新,可以理解為這種volatile不會出現一般變數的緩存操作,而讀取線程每次必須根據前一個線程的可見域裡面重新讀取該變數的值,而不是直接讀取。 當某個線程第一次去訪問某個對象的域的時候,它要麼初始化該對象的值,要麼從其他寫入線程可見域裡面去讀取該對象的值;這里結合上邊理解,在滿足某種條件下,該線程對某對象域的值的讀取是直接讀取,有些時候卻需要重新讀取。這里需要小心一點的是,在並發編程裡面,不好的一個實踐就是使用一個合法引用去引用不完全構造的對象,這種情況在從其他寫入線程可見域裡面進行數據讀取的時候發生頻率比較高。從編程角度上講,在構造函數裡面開啟一個新的線程是有一定的風險的,特別是該類是屬於一個可子類化的類的時候。Thread.start由調用線程啟動,然後由獲得該啟動的線程釋放鎖具有相同的「短暫記憶效應」,如果一個實現了Runnable介面的超類在子類構造子執行之前調用了Thread(this).start()方法,那麼就可能使得該對象在線程方法run執行之前並沒有被完全初始化,這樣就使得一個指向該對象的合法引用去引用了不完全構造的一個對象。同樣的,如果創建一個新的線程T並且啟動該線程,然後再使用線程T來創建對象X,這種情況就不能保證X對象裡面所有的屬性針對線程T都是可見的除非是在所有針對X對象的引用中進行同步處理,或者最好的方法是在T線程啟動之前創建對象X。 若一個線程終止,所有的變數值都必須從工作內存中刷到主存,比如,如果一個同步線程因為另一個使用Thread.join方法的線程而終止,那麼該線程的可見域針對那個線程而言其發生的改變以及產生的一些影響是需要保證可知道的。 注意:如果在同一個線程裡面通過方法調用去傳一個對象的引用是絕對不會出現上邊提及到的可見性問題的。JMM保證所有上邊的規定以及關於內存可見性特性的描述——一個特殊的更新、一個特定欄位的修改都是某個線程針對其他線程的一個「可見性」的概念,最終它發生的場所在內存模型中Java線程和線程之間,至於這個發生時間可以是一個任意長的時間,但是最終會發生,也就是說,Java內存模型中的可見性的特性主要是針對線程和線程之間使用內存的一種規則和約定,該約定由JMM定義。
不僅僅如此,該模型還允許不同步的情況下可見性特性。比如針對一個線程提供一個對象或者欄位訪問域的原始值進行操作,而針對另外一個線程提供一個對象或者欄位刷新過後的值進行操作。同樣也有可能針對一個線程讀取一個原始的值以及引用對象的對象內容,針對另外一個線程讀取一個刷新過後的值或者刷新過後的引用。
盡管如此,上邊的可見性特性分析的一些特徵在跨線程操作的時候是有可能失敗的,而且不能夠避免這些故障發生。這是一個不爭的事實,使用同步多線程的代碼並不能絕對保證線程安全的行為,只是允許某種規則對其操作進行一定的限制,但是在最新的JVM實現以及最新的Java平台中,即使是多個處理器,通過一些工具進行可見性的測試發現其實是很少發生故障的。跨線程共享CPU的共享緩存的使用,其缺陷就在於影響了編譯器的優化操作,這也體現了強有力的緩存一致性使得硬體的價值有所提升,因為它們之間的關系在線程與線程之間的復雜度變得更高。這種方式使得可見度的自由測試顯得更加不切實際,因為這些錯誤的發生極為罕見,或者說在平台上我們開發過程中根本碰不到。在並行程開發中,不使用同步導致失敗的原因也不僅僅是對可見度的不良把握導致的,導致其程序失敗的原因是多方面的,包括緩存一致性、內存一致性問題等。
可排序性(Ordering):
可排序規則在線程與線程之間主要有下邊兩點: 從操作線程的角度看來,如果所有的指令執行都是按照普通順序進行,那麼對於一個順序運行的程序而言,可排序性也是順序的 從其他操作線程的角度看來,排序性如同在這個線程中運行在非同步方法中的一個「間諜」,所以任何事情都有可能發生。唯一有用的限制是同步方法和同步塊的相對排序,就像操作volatile欄位一樣,總是保留下來使用 【*:如何理解這里「間諜」的意思,可以這樣理解,排序規則在本線程裡面遵循了第一條法則,但是對其他線程而言,某個線程自身的排序特性可能使得它不定地訪問執行線程的可見域,而使得該線程對本身在執行的線程產生一定的影響。舉個例子,A線程需要做三件事情分別是A1、A2、A3,而B是另外一個線程具有操作B1、B2,如果把參考定位到B線程,那麼對A線程而言,B的操作B1、B2有可能隨時會訪問到A的可見區域,比如A有一個可見區域a,A1就是把a修改稱為1,但是B線程在A線程調用了A1過後,卻訪問了a並且使用B1或者B2操作使得a發生了改變,變成了2,那麼當A按照排序性進行A2操作讀取到a的值的時候,讀取到的是2而不是1,這樣就使得程序最初設計的時候A線程的初衷發生了改變,就是排序被打亂了,那麼B線程對A線程而言,其身份就是「間諜」,而且需要注意到一點,B線程的這些操作不會和A之間存在等待關系,那麼B線程的這些操作就是非同步操作,所以針對執行線程A而言,B的身份就是「非同步方法中的『間諜』。】
同樣的,這僅僅是一個最低限度的保障性質,在任何給定的程序或者平台,開發中有可能發現更加嚴格的排序,但是開發人員在設計程序的時候不能依賴這種排序,如果依賴它們會發現測試難度會成指數級遞增,而且在復合規定的時候會因為不同的特性使得JVM的實現因為不符合設計初衷而失敗。
注意:第一點在JLS(Java Language Specification)的所有討論中也是被採用的,例如算數表達式一般情況都是從上到下、從左到右的順序,但是這一點需要理解的是,從其他操作線程的角度看來這一點又具有不確定性,對線程內部而言,其內存模型本身是存在排序性的。【*:這里討論的排序是最底層的內存裡面執行的時候的NativeCode的排序,不是說按照順序執行的Java代碼具有的有序性質,本文主要分析的是JVM的內存模型,所以希望讀者明白這里指代的討論單元是內存區。】 JMM最初設計的時候存在一定的缺陷,這種缺陷雖然現有的JVM平台已經修復,但是這里不得不提及,也是為了讀者更加了解JMM的設計思路,這一個小節的概念可能會牽涉到很多更加深入的知識,如果讀者不能讀懂沒有關系先看了文章後邊的章節再返回來看也可以。
1)問題1:不可變對象不是不可變的
學過Java的朋友都應該知道Java中的不可變對象,這一點在本文最後講解String類的時候也會提及,而JMM最初設計的時候,這個問題一直都存在,就是:不可變對象似乎可以改變它們的值(這種對象的不可變指通過使用final關鍵字來得到保證),(Publis Service Reminder:讓一個對象的所有欄位都為final並不一定使得這個對象不可變——所有類型還必須是原始類型而不能是對象的引用。而不可變對象被認為不要求同步的。但是,因為在將內存寫方面的更改從一個線程傳播到另外一個線程的時候存在潛在的延遲,這樣就使得有可能存在一種競態條件,即允許一個線程首先看到不可變對象的一個值,一段時間之後看到的是一個不同的值。這種情況以前怎麼發生的呢?在JDK 1.4中的String實現里,這兒基本有三個重要的決定性欄位:對字元數組的引用、長度和描述字元串的開始數組的偏移量。String就是以這樣的方式在JDK 1.4中實現的,而不是只有字元數組,因此字元數組可以在多個String和StringBuffer對象之間共享,而不需要在每次創建一個String的時候都拷貝到一個新的字元數組里。假設有下邊的代碼:
String s1 = /usr/tmp;
String s2 = s1.substring(4); // /tmp
這種情況下,字元串s2將具有大小為4的長度和偏移量,但是它將和s1共享「/usr/tmp」裡面的同一字元數組,在String構造函數運行之前,Object的構造函數將用它們默認的值初始化所有的欄位,包括決定性的長度和偏移欄位。當String構造函數運行的時候,字元串長度和偏移量被設置成所需要的值。但是在舊的內存模型中,因為缺乏同步,有可能另一個線程會臨時地看到偏移量欄位具有初始默認值0,而後又看到正確的值4,結果是s2的值從「/usr」變成了「/tmp」,這並不是我們真正的初衷,這個問題就是原始JMM的第一個缺陷所在,因為在原始JMM模型裡面這是合理而且合法的,JDK 1.4以下的版本都允許這樣做。
2)問題2:重新排序的易失性和非易失性存儲
另一個主要領域是與volatile欄位的內存操作重新排序有關,這個領域中現有的JMM引起了一些比較混亂的結果。現有的JMM表明易失性的讀和寫是直接和主存打交道的,這樣避免了把值存儲到寄存器或者繞過處理器特定的緩存,這使得多個線程一般能看見一個給定變數最新的值。可是,結果是這種volatile定義並沒有最初想像中那樣如願以償,並且導致了volatile的重大混亂。為了在缺乏同步的情況下提供較好的性能,編譯器、運行時和緩存通常是允許進行內存的重新排序操作的,只要當前執行的線程分辨不出它們的區別。(這就是within-thread as-if-serial semantics[線程內似乎是串列]的解釋)但是,易失性的讀和寫是完全跨線程安排的,編譯器或緩存不能在彼此之間重新排序易失性的讀和寫。遺憾的是,通過參考普通變數的讀寫,JMM允許易失性的讀和寫被重排序,這樣以為著開發人員不能使用易失性標志作為操作已經完成的標志。比如:
Map configOptions;
char[] configText;
volatile boolean initialized = false;
// 線程1
configOptions = new HashMap();
configText = readConfigFile(filename);
processConfigOptions(configText,configOptions);
initialized = true;
// 線程2
while(!initialized)
sleep();
這里的思想是使用易失性變數initialized擔任守衛來表明一套別的操作已經完成了,這是一個很好的思想,但是不能在JMM下工作,因為舊的JMM允許非易失性的寫(比如寫到configOptions欄位,以及寫到由configOptions引用Map的欄位中)與易失性的寫一起重新排序,因此另外一個線程可能會看到initialized為true,但是對於configOptions欄位或它所引用的對象還沒有一個一致的或者說當前的針對內存的視圖變數,volatile的舊語義只承諾在讀和寫的變數的可見性,而不承諾其他變數,雖然這種方法更加有效的實現,但是結果會和我們設計之初大相徑庭。

⑷ intel fortran如何實現單機多核並行運算

請使用openmp。

打開OpenMP支持,方法如下:

選擇項目(Project) -> 屬性(property) -> Fortran -> 語言(Language),在 Process OpenMP Directives 選項中選擇 Generate Parallel Code (/Qopenmp),點擊確定以打開 OpenMP 支持。

示例代碼:

⑸ 編寫C++語言程序是用英特爾 C++ 編譯器好還是微軟的VC++2008

都可以 關鍵看你要用什麼 Intel C++的編譯器效率比較高 對多核多線程的優化也比較好

⑹ 如何使用android的ndk編譯器 編譯c++的庫

1. 概述 首先回顧一下 Android NDK 開發中,Android.mk 和 Application.mk 各自的職責。 Android.mk,負責配置如下內容: (1) 模塊名(LOCAL_MODULE) (2) 需要編譯的源文件(LOCAL_SRC_FILES) (3) 依賴的第三方庫(LOCAL_STATIC_LIBRARIES,LOCAL_SHARED_LIBRARIES) (4) 編譯/鏈接選項(LOCAL_LDLIBS、LOCAL_CFLAGS) Application.mk,負責配置如下內容: (1) 目標平台的ABI類型(默認值:armeabi)(APP_ABI) (2) Toolchains(默認值:GCC 4.8) (3) C++標准庫類型(默認值:system)(APP_STL) (4) release/debug模式(默認值:release) 由此我們可以看到,本文所涉及的編譯選項在Android.mk和Application.mk中均有出現,下面我們將一個個詳細介紹。 2. APP_ABI ABI全稱是:Application binary interface,即:應用程序二進制介面,它定義了一套規則,允許編譯好的二進制目標代碼在所有兼容該ABI的操作系統和硬體平台中無需改動就能運行。(具體的定義請參考 網路 或者 維基網路 ) 由上述定義可以判斷,ABI定義了規則,而具體的實現則是由編譯器、CPU、操作系統共同來完成的。不同的CPU晶元(如:ARM、Intel x86、MIPS)支持不同的ABI架構,常見的ABI類型包括:armeabi,armeabi-v7a,x86,x86_64,mips,mips64,arm64-v8a等。 這就是為什麼我們編譯出來的可以運行於Windows的二進製程序不能運行於Mac OS/Linux/Android平台了,因為CPU晶元和操作系統均不相同,支持的ABI類型也不一樣,因此無法識別對方的二進製程序。 而我們所說的「交叉編譯」的核心原理也跟這些密切相關,交叉編譯,就是使用交叉編譯工具,在一個平台上編譯生成另一個平台上的二進制可執行程序,為什麼可以做到?因為交叉編譯工具實現了另一個平台所定義的ABI規則。我們在Windows/Linux平台使用Android NDK交叉編譯工具來編譯出Android平台的庫也是這個道理。 這里給出最新 Android NDK 所支持的ABI類型及區別: 那麼,如何指定ABI類型呢?在 Application.mk 文件中添加一行即可: APP_ABI := armeabi-v7a //只編譯armeabi-v7a版本 APP_ABI := armeabi armeabi-v7a //同時編譯armeabi,armeabi-v7a版本 APP_ABI := all //編譯所有版本 3. LOCAL_LDLIBS Android NDK 除了提供了Bionic libc庫,還提供了一些其他的庫,可以在 Android.mk 文件中通過如下方式添加依賴: LOCAL_LDLIBS := -lfoo 其中,如下幾個庫在 Android NDK 編譯時就默認鏈接了,不需要額外添加在 LOCAL_LDLIBS 中: (1) Bionic libc庫 (2) pthread庫(-lpthread) (3) math(-lmath) (4) C++ support library (-lstdc++) 下面我列了一個表,給出了可以添加到「LOCAL_LDLIBS」中的不同版本的Android NDK所支持的庫: 下面是我總結的一些常用的CFLAGS編譯選項: (1)通用的編譯選項 -O2 編譯優化選項,一般選擇O2,兼顧了優化程度與目標大小 -Wall 打開所有編譯過程中的Warning -fPIC 編譯位置無關的代碼,一般用於編譯動態庫 -shared 編譯動態庫 -fopenmp 打開多核並行計算, -Idir 配置頭文件搜索路徑,如果有多個-I選項,則路徑的搜索先後順序是從左到右的,即在前面的路徑會被選搜索 -nostdinc 該選項指示不要標准路徑下的搜索頭文件,而只搜索-I選項指定的路徑和當前路徑。 --sysroot=dir 用dir作為頭文件和庫文件的邏輯根目錄,例如,正常情況下,如果編譯器在/usr/include搜索頭文件,在/usr/lib下搜索庫文件,它將用dir/usr/include和dir/usr/lib替代原來的相應路徑。 -llibrary 查找名為library的庫進行鏈接 -Ldir 增加-l選項指定的庫文件的搜索路徑,即編譯器會到dir路徑下搜索-l指定的庫文件。 -nostdlib 該選項指示鏈接的時候不要使用標准路徑下的庫文件 (2) ARM平台相關的編譯選項 -marm -mthumb 二選一,指定編譯thumb指令集還是arm指令集 -march=name 指定特定的ARM架構,常用的包括:-march=armv6, -march=armv7-a -mfpu=name 給出目標平台的浮點運算處理器類型,常用的包括:-mfpu=neon,-mfpu=vfpv3-d16 -mfloat-abi=name 給出目標平台的浮點預算ABI,支持的參數包括:「soft」, 「softfp」 and 「hard」

⑺ fatal error C1076: compiler limit : internal heap limit reached; use /Zm to specify a higher limit

意思是:
編譯器限制:內部堆達到了最大的限制。使用/zm來指定一個更大的限制值。

我覺得有可能是你分配了太多的內存,或者是指定了太小的堆。建議你拿到別人默認設置的vc++上面編譯一下試試看,然後才能確定到底是代碼的問題還是編譯環境設置的問題

⑻ 為什麼在多核多線程程序中要慎用volatile關鍵字

a. 避免用通用寄存器對內存讀寫的優化。編譯器常做的一種優化就是:把常用變數的頻繁讀寫弄到通用寄存器中,最後不用的時候再存回內存中。但是如果某個內存地址中的值是由片外決定的(例如另一個線程或是另一個設備可能更改它),那就需要volatile關鍵字了。(感謝Kenny老師指正)
b.硬體寄存器可能被其他設備改變的情況。例如一個嵌入式板子上的某個寄存器直接與一個測試儀器連在一起,這樣在這個寄存器的值隨時可能被那個測試儀器更改。在這種情況下如果把該值設為volatile屬性的,那麼編譯器就會每次都直接從內存中去取這個值的最新值,而不是自作聰明的把這個值保留在緩存中而導致讀不到最新的那個被其他設備寫入的新值。
c. 同一個物理內存地址M有兩個不同的內存地址的情況。例如兩個程序同時對同一個物理地址進行讀寫,那麼編譯器就不能假設這個地址只會有一個程序訪問而做緩存優化,所以程序員在這種情況下也需要把它定義為volatile的。

⑼ intel visual fortran compiler幹嘛用的

Visual Numerics Inc已於2004年初完成與Intel的結盟,將當時的IMSL Fortran Library的新版本v5.0整合在Intel Visual Fortran系列產品之專業版(承襲購並之Compaq Visual Fortran功能架構)中。2005.6月份發布其最新版本Intel Visual Fortran Compiler v9.0.018

針對Intel® CPU Pentium® 4, Xeon�6�4, Centrino�6�4 Itanium® 做最佳的福傳編譯,支持OpenMP及Auto-Parallelism特色. 「英特爾R Visual Fortran 編譯器Windows* 版」將Compaq Visual Fortran* (CVF) 語言的豐富功能與英特爾代碼生成及優化技術結合在一起,構成面向英特爾體系結構的下一代Fortran 編譯器。它提供250 多條CVF 與英特爾Fortran 命令及同義詞,使編譯器更加易於使用,同時仍能作為插件融入Microsoft Visual Studio 環境,並提供直接來自英特爾的技術支持。此編譯器是一套功能齊備的Fortran 95 編譯器,具有先進的優化功能,可以使Fortran 應用程序在英特爾R IA-32 與安騰2 處理器上快速運行。英特爾® 視覺FORTRAN 編譯器為窗口* 標記一個里程碑為FORTRAN 開發商。它帶來Compaq 視覺FORTRAN * 語言特色與英特爾編譯器代碼世代和優化技術一起。

性能、兼容性、技術支持:採用「英特爾 Visual Fortran 編譯器 9.0 Windows* 版」,可以提高應用程序速度,並保護您在開發工具上所作的投資。先進的優化功能可以給最新英特爾® 處理器上運行的應用程序帶來出眾的性能。本產品包含標准版與專業版。「英特爾® Visual Fortran 編譯器專業版」包含 Visual Numerics, Inc. 的「IMSL* Fortran 函數庫6.0」。
目前版本號最高的Intel Fortran編譯器,需要Visual Studio 6.0以上支持,可以生成更適用於Intel晶元的高效程序,是Intel平台下最優秀的Fortran語言編譯器。大家可以考慮丟掉Fortran 77編譯系統了:P
Fortran,是由Formula Translation兩個字所組合而成,意思是公式翻譯。它是世界上第一個被正式採用並流傳至今的高級編程語言。

性能、兼容性、技術支持
使用「英特爾® Visual Fortran 編譯器 Windows* 版」,可以讓您的應用程序在英特爾® 處理器上取得前所未有的絕佳性能。

此編譯器有標准版與專業版這兩個版本提供。「英特爾® Visual Fortran 編譯器專業版」包含 Visual Numerics, Inc. 的「IMSL* Fortran 函數庫 5.0」。

客戶評價:

「在英特爾編譯器的幫助下,我們開發了大型海洋模型,充分利用了在基於英特爾的系統上所作的投資。在使用『英特爾 Visual Fortran 編譯器 Windows 版』編譯代碼時,我發現,與以前的版本相比,性能提高了大約 20%。」
- Xianyao Chen 博士
海洋模型小組組長
中國第一海洋研究所

「『英特爾 Fortran 編譯器 7.0』堪稱一流,『英特爾 Visual Fortran 8.0』做得還要好。英特爾將 Compaq Visual Fortran 與『英特爾 Fortran』中最優秀的功能結合在一起,實現了一次巨大的飛躍。」現在為9.0最新版!

sual Fortran 與『英特爾 Fortran』中最優秀的功能結合在一起,實現了一次巨大的飛躍。」現在為9.0最新版!

⑽ Java優勢有哪些

JAVA的優勢是什麼?

Java語言是目前的排行第一的語言,其優勢也是非常突出的,那麼具體體現在哪裡吶?

我來給你說一下Java的優勢:

1.java的風格類似C++但不同於C++,從某種意義上講,java是C++的一個變種;

2.java摒棄了C、C++中的容易引發錯誤和難以理解的指針,結構,以及內存管理等;

3.java提供了豐富的類庫,很方便開發程序;

4.java是完全面向對象的語言,支持 繼承,重載,多態等面向對象的特性;

5.C++是面向對象和面向過程的混合語言, C是純面向過程的語言;

6.java是一種強類型的語言,比C/C++檢查還要嚴格,java區分大小寫字母;

7.java提供了自動垃圾回收機制gc,有效避免了C、C++的內存泄漏問題;

8.java禁止非法訪問內存,因為java沒有指針,內存的申請和釋放;

9.跨平台,java的源代碼編譯成結構中立的中間格式,這種格式與機器無關,只要在安裝有JVM(java虛擬機)的電腦上,都能運行這種與機器無關的中間文件;java一次編譯,到處運行;

10.對於不同的操作系統,會有不同的java虛擬機,這也就決定了java的可移植性;

11.java支持多線程,簡單理解,如果是單核CPU,那麼會通過時間片輪轉的方式,多線程執行程序,如果是多核CPU,那麼就可以理解為,兩個或多個線程同時運行。


一、做網站

Java可以用來做網站,很多大型網站都是用Java寫的,比如我們熟悉的B站,所以想學習Java的同學還可以負責網站方面的製作,這方面的崗位(網站開發)也比較多,一直以來都相當流行。

二、做安卓軟體

安卓是基於Linux的操作系統,其中源代碼就是Java,市面上所有的安卓手機都是修改Java運行的,對於更多的開發人員來說,他們更多的時間是花在開發APP上面。你隨便打開一個App應用,他們就是用Java語言做的。

三、做游戲

電腦上的大多數游戲也是用Java來開發的,最經典的就是《我的世界》,還有當今世界最具影響力的游戲英雄聯盟,吃雞也是用Java寫的

四、寫軟體

很多編程語言都是可以來寫軟體的,但Java是現在應用最廣泛的,比如:企業級應用開發,還有OA、郵箱、物流、醫療、投票、金融、考試、礦山等信息方面的系統,Java都佔有極為重要的地位。現在國內的最熱門的就是手機應用,學習Java去做手機應用還是比較吃香的。

說啦這么多那麼應該如何學習Java那?

在這個里我使用腦圖給大家出一個,Java的學習線路供大家參考:

Java在市場中的佔有率是非常之高的,希望大都成為優秀的程序員!!!

熱點內容
中國有ip6伺服器嗎 發布:2025-07-04 17:58:56 瀏覽:724
第六章編譯原理答案 發布:2025-07-04 17:37:55 瀏覽:39
php內存優化 發布:2025-07-04 17:25:54 瀏覽:662
威綸觸摸屏如何設置時間限制密碼 發布:2025-07-04 17:25:50 瀏覽:418
python列表的遍歷 發布:2025-07-04 17:24:20 瀏覽:22
編譯基本塊 發布:2025-07-04 17:23:06 瀏覽:748
scl語言編程 發布:2025-07-04 17:23:05 瀏覽:991
oracle用戶連接資料庫連接 發布:2025-07-04 17:20:20 瀏覽:939
我的世界純生存伺服器推薦死亡不掉落 發布:2025-07-04 17:06:14 瀏覽:348
方舟編譯器可以用於p20嗎 發布:2025-07-04 17:00:17 瀏覽:786