HPX高性能并行編程1:C++標準和標準庫
1 C++、C++ 標準和 C++ 標準庫
1.1 C++、C++ 標準和并行編程簡史

C++ 基于 Dennis Ritchie 在貝爾實驗室工作期間于 1969 年至 1973 年創建的編程語言 C。1973 年,Ritchie 的編譯器被用于編譯 PDP-11 計算機的 Unix 內核。這是第一次用匯編語言以外的語言編寫操作系統。
遺憾的是,直到 1989 年,官方的 C 標準才出臺,各種編譯器實現都導致了未指定的行為。然而,當時有一個非官方的規范,即 K&R C,它基于 Kernighan 和 Ritchie 于 1978 年撰寫的書籍。多年來,C 編程語言中添加了許多語言特性。并非所有編譯器都支持所有這些特性。因此,人們一致認為需要一個官方的 C 標準。
美國國家標準協會 (ANSI) 于 1983 年成立了一個委員會。該協會于 1989 年通過了 ANSI X3.159-1989《編程語言 C》標準。這是 C 編程語言的第一個官方標準,稱為 C 89。然而,該標準是由 ANSI 發布的,并非國際標準。因此,國際標準化組織 (ISO) 于 1990 年修訂了 C 89 標準,并將其發布為 ISO/IEC 9899:1990。由此,第一個國際標準 C 90 應運而生。需要注意的是,C 89 和 C 90 是同一個標準,只是名稱不同。后來,C 99 (ISO/IEC 9899:1999) 標準發布。2011 年、2018 年和 2023 年,C 11、C 18 和 C 23 標準相繼發布。
從 1990 年起,C 語言實現了標準化,因此所有希望符合標準的編譯器都必須遵循 C 標準。這極大地簡化了為不同機器和架構編寫代碼的過程??梢哉f,認識到標準在編程中的價值是當時最偉大的技術進步。
與此同時,1978年,在AT&T工作的Bjarne Stroustrup開始開發“帶類的C語言”。Stroustrup希望以Simula67的風格編寫高效的系統程序。因此,他為C語言添加了更好的類型檢查、數據抽象和面向對象編程。第一個版本于1983年在內部使用,后來更名為C++。1985年,第一個商業實現發布。然而,當時還沒有官方標準,但Stroustrup出版了一本書,就像Kernighan和Ritchie那樣。
正如我們在標準化過程中發現的那樣,程序員能夠分離關注點,軟件的運行效果就越好。標準幫助用戶將對編譯器實現和機器架構的擔憂與代碼邏輯區分開來。類似地,許多C++語言特性和庫代表了進一步的關注點分離努力,使程序員能夠一次專注于更少的問題。
類允許將字符串、iostream 或復數等類型的基本邏輯與使用它們的代碼和實現它們的代碼分開。雖然可以使用 C 語言進行面向對象編程(主要是因為它支持結構體),但 C++ 通過運算符重載、構造函數和析構函數、私有數據和一致性檢查為面向對象范式提供了額外的支持。
在模板出現之前,程序員如果想要使用向量或映射之類的類型,必須為每種類型重新實現類似的邏輯多次。這種重新實現帶來了維護方面的挑戰,因為每當需要修改代碼時,都必須更新每一段重復的邏輯。模板和泛型編程改變了這種情況。同樣,用 C 語言編寫泛型程序也是可行的。在 C++ 的早期,諸如映射之類的類是通過大量使用 C 預處理器來實現的。然而,通過模板,C++ 為這種編程風格提供了更好的支持和錯誤檢查。
標準以及類和泛型使程序員能夠查看程序的各個部分,而無需一次性理解整段代碼。通過允許程序員專注于各個部分,編寫大型復雜代碼的任務變得更容易處理。
然而,并行編程仍然是一個挑戰。為什么呢?
作為編程社區對標準價值和力量的認可的一部分,MPI 標準于 1994 年誕生。雖然我們不會在這個獨立于語言的并行編程庫上花費太多時間,但我們注意到它仍然是分布式并行編程中最廣泛認可和實施的跨語言標準。曾有一段短暫的時期,人們嘗試將標準 C++ 綁定到 MPI,但這些綁定存在問題,最終在 MPI 3.0 標準中被移除。
遺憾的是,雖然 MPI 使得分布式編程在各種平臺和各種語言上都變得可靠,但它并沒有讓編寫并行代碼變得特別容易。
1997 年,OpenMP 標準開始發展。到 2005 年,它確定了一種在 FORTRAN 和 C/C++ 上實現單節點并行性能的標準方法。OpenMP 的一個優點是它在注釋或指令中使用聲明式并行。這種機制使得將代碼邏輯與并行性分離變得更加容易。
使用 OpenMP 和 MPI,可以相當簡單地實現批量同步編程風格,其中一組線程以鎖步方式工作并交換信息。這樣的代碼在幾乎所有超級計算機上都具有良好的擴展性和高性能。它們還經常使用屏障機制,使所有線程和進程在某個時刻同步。
許多程序員并不滿足于這些機制所能實現的效果。C++ 11 引入了線程、互斥量、原子操作、Future 和異步方法調用,為我們提供了在單節點內進行并行編程的標準。它還引入了智能指針,幫助清理多個線程持有的數據。
C++ 17 和 C++ 20 都為程序員提供了重要的附加功能,包括并行算法。
然而,充分利用任何機器至今仍然是一個挑戰。本書將探討目前可能實現的目標,并酌情提供編程方法和風格的指導。
我們指出,程序員應盡可能將代碼的并行邏輯與試圖執行的計算清晰地隔離開來。模塊化和關注點分離的原則仍然是創建成功的大型程序的關鍵。
此外,C++ 教學的標準化也在不斷推進。 SG20 的《Guidelines for Teaching C++ to beginners》(ISO P1389)是針對入門級 C++ 教學指南的一次嘗試。在第一階段,即基礎知識部分,本書涵蓋了以下基礎知識:容器、范圍、lambda 函數和迭代器用法。在第二階段,該提案推薦了以下 C++ 特性:智能指針和并行算法。在第三階段,該提案推薦了以下 C++ 特性:泛型編程和無需模板元編程的模板。本書更進一步,重點關注并行和分布式編程。下圖總結了 C++ 標準的歷史,并重點介紹了本書中使用的特性。

參考資料
- 軟件測試精品書籍文檔下載持續更新 https://github.com/china-testing/python-testing-examples 請點贊,謝謝!
- 本文涉及的python測試開發庫 謝謝點贊! https://github.com/china-testing/python_cn_resouce
- python精品書籍下載 https://github.com/china-testing/python_cn_resouce/blob/main/python_good_books.md
- Linux精品書籍下載 http://www.rzrgm.cn/testing-/p/17438558.html
- python八字排盤 https://github.com/china-testing/bazi
- 聯系方式:釘ding或V信: pythontesting
1.2 標準模板庫 (STL:Standard Template Library) 和 C++ 標準庫
Dave Musser 于 1971 年使用泛型編程完成了泛型庫的初稿。Dave Musser 和 Alexander Stepanov 在中創造了“泛型編程”一詞。Alexander Stepanov 繼續研究 Musser 的泛型庫思想,并于 1987 年開發了第一個使用 Ada 編程語言的庫。Stepanov 和 Lee 在惠普 (HP) 工作期間將他們的庫命名為標準模板庫 (STL)。后來,STL 以開源形式發布。STL 是第一個用于 C++ 數據結構和算法的泛型庫。STL 的設計圍繞四個理念:泛型編程、抽象性、值語義和馮·諾依曼計算模型。如今,STL 已不再維護。然而,Stepanov 和 Lee 于 1993 年聯系了 C++ 標準化委員會,并提交了他們的庫,希望將其納入 C++ 標準。經過反復討論,該提案于 1994 年 7 月在 ANSI/ISO 委員會會議上獲得批準。這三位研究人員為 C++ 標準中定義的 C++ 標準庫的規范奠定了基礎。此外,Stepanov 和 McJones 還基于堅實的數學基礎撰寫了《Elements of programming》一書,供實際編程使用。
請注意,標準模板庫和 C++ 標準庫是兩個不同的東西。C++ 標準庫是由 C++ 標準指定的。C++ 標準指定的 C++ 標準庫有許多可用的實現。下表 2.1 列出了最常見的活躍實現。C++ 標準庫有一個由 Cray? 開發的商業實現,即 Cray? C++ 標準庫。所有其他實現均可作為開源軟件獲取。 Microsoft? 發布了用于 MSVC 工具集和 Visual Studio IDE 的 Microsoft? C++ 標準庫。這是 Windows 操作系統最常用的實現。第二個 C++ 標準庫由是 NVIDIA? C++ 標準庫。該庫的特殊之處在于其算法和數據結構可以在 CPU 和 NVIDIA? GPU 上使用。所有其他庫都只能在 CPU 上運行。Linux 操作系統上最常見的 C++ 標準庫是 GNU C++ 標準庫。另一個 C++ 標準庫是 LLVM C++ 標準庫。C++ 標準庫的最新實現是 HPX,即 C++ 并行和并發標準庫。本書將使用 GNU C++ 標準庫和 Microsoft C++ 標準庫作為示例。對于分布式示例,我們將使用 C++ 并行和并發標準庫 (HPX)。有關更多詳細信息以及每個 C++ 標準庫中可用的庫特性,請參閱表 2.1。表 3 列出了 C++ 標準庫的各種實現。除一個庫外,所有庫均采用開源許可證。

1.3 C++ 編譯器
以下是可用的 C++ 編譯器。請注意,可用的編譯器還有很多,但我們只討論那些最知名且在超級計算機上最常用的編譯器。首先,我們考慮各公司提供的編譯器。在 Cray? 超級計算機上,尤其是在使用消息傳遞接口 (MPI) 進行分布式計算時,會使用 HPE? Cray? 編譯器。英特爾? 的 icc 編譯器針對英特爾? CPU 進行了特殊優化。同樣,IBM? XL 編譯器針對 IBM? Power? 架構進行了特殊優化,AMD? 的 AOCC 編譯器針對 AMD? CPU 進行了特殊優化,富士通? 的 fcc 編譯器針對 A64FX? 架構進行了特殊優化,Arm? 的 armclang++ 編譯器針對 Arm? 架構進行了特殊優化。微軟? 為 Windows 操作系統提供了 Visual C++。最后,NVIDIA? 提供了 pgc++ 編譯器,它是 NVIDIA? HPC SDK 的一部分。
以下是可用的社區驅動編譯器。首先是 GNU 項目的 g++。該編譯器在 Linux 上被廣泛用作默認的 C++ 編譯器。另一個編譯器是 LLVM 項目的 clang++。

本書中的示例已使用 Visual C++、clang++ 和 g++ 編譯器測試。有關推薦編譯器和版本的更多詳細信息,請參閱附錄 C。但是,由于 C++ 已實現 ISO 標準化,所有支持 C++ 17 或 C++ 20 的編譯器都應該能夠正常工作。
浙公網安備 33010602011771號