高性能计算的线程模型:Pthreads 还是 OpenMP
簡介
UNIX 操作系統多年來一直支持線程,這是 UNIX 在服務器系統上異常活躍的主要原因之一。在過去幾年間,Linux* 一直宣傳自己通過改進線程的內核支持而在服務器上的出色表現。例如,kernel 最近發布的 2.6 版增加了全新的調度程序,能夠通過可以在 Linux 系統上切換的線程來大幅度優化速度。kernel 之前的版本(2.4 版--Linux kernel 使用偶數代表發布的版本,奇數代表正在開發的版本)同樣根據線程能力的大幅度改進來劃分。這些進步有助于將 Linux 放在服務器上和放入支持高性能計算(HPC)的站點中。此外,Linux 放棄其原有的線程 API(稱為 Linux 線程)并采用 Pthreads 作為其固有的線程界面,連接目前可用的大部分 UNIX 變量。
然而,Linux 開發人員(如使用 UNIX 和 Windows* 的程序員)可以使用稱為 OpenMP* 的第二種線程 API,這由服務器廠商聯盟精心設計而成。本文將 Pthreads 和 OpenMP 進行比較,并嘗試確定哪一種能夠使開發人員受益最多。
Pthreads 是什么?
Pthreads 是 IEEE(電子和電氣工程師協會)委員會開發的一組線程接口,負責指定便攜式操作系統接口(POSIX)。Pthreads 中的 P 表示 POSIX,實際上,Pthreads 有時候也代表 POSIX 線程。基本上,POSIX 委員會定義了一系列基本功能和數據結構,它希望能夠被大量廠商采用,因此線程代碼能夠輕松地在操作系統上移植。委員會的夢想由 UNIX 廠商實現了,他們都大規模實施 Pthreads。(最著名的例外就是 Sun,它繼續采用 Solaris* 線程作為其主要線程 API。)由于 Linux 的采用和移植到 Windows 平臺,Pthreads 的可能性一直被進一步擴展。
Pthreads 指定 API 來處理線程要求的大部分行為。這些行為包括創建和終止線程、等待線程完成、以及管理線程之間的交互。后面的目錄中存在各種鎖定機制,能夠阻止兩個線程同時嘗試修改相同的數據值:互斥體、條件變量和信號量。(從技術上講,信號量不是 Pthreads 的一部分,但是它們從概念上更接近于與線程合作,而且可用于 Pthreads 能夠運行的所有系統上。)
為了使用 Pthreads,開發人員必須為這一 API 專門編寫代碼。這就意味著它們必須包括標頭文件、宣布 Pthreads 數據結構、并調用 Pthreads 指定的函數。基本上,此流程與使用其它庫沒有不同。和 UNIX 以及 Linux 上的其它庫一樣,Pthreads 庫只是簡單地鏈接到應用代碼(通過 -lpthread 參數)。
雖然 Pthreads 庫相當復雜(盡管不像一些其它固有的 API 設置那樣廣泛)而且顯然具有便攜性,但是全部固有線程 API 常用的嚴格限制條件也使它非常艱難:它需要大量線程專用代碼。換言之,為 Pthreads 進行編碼就要在線程模型中建立代碼庫,這是不可回避的。此外,一些決策(如需要使用的線程數據)也將成為程序中的硬編碼。作為這些限制的交換條件,Pthreads 能提供對于線程操作的廣泛控制--這是一個固有的低級 API,通常要求多個步驟來執行簡單的線程任務。例如,使用線程循環來通過大型數據塊需要宣布線程結構、單獨創建線程、計算通向每個線程的循環并分配到線程、最終處理線程終止--所有這些必須由開發人員進行編碼。如果循環不僅僅是簡單的疊代,則線程指定代碼的數量將顯著增加。為了公平起見,對于如此多代碼的需求存在于所有本地線程 API 中,而不僅僅是 Pthreads。
鑒于需要執行直接操作的線程代碼的數量,開發人員一直在尋找更簡單的 Pthreads 替代品。
OpenMP 是什么?
1997 年,一些廠商攜手合作,在硬件制造商 Silicon Graphics 的支持下組成了新的線程接口。他們共同的問題是主要的時間操作系統全部利用了完全不同的線程編程方法。UNIX 使用 Pthreads、Sun 使用 Solaris 線程、Windows 使用自己的 API、而 Linux 則使用 Linux 線程(直到其后來采用 Pthreads)。委員會希望設計出能夠支持代碼庫不需要改變即可在 Windows 和 UNIX/Linux 上平等運行的 API。1998 年,它提供了第一個稱為 OpenMP 的 API 規范(在這些日子里,“開放”這個詞匯與多廠商支持的概念相關,是指開放系統,而不是現在的開放源代碼的含義。)
OpenMP 規范包括 API、一組編譯指示、以及對 OpenMP 指定環境變量的幾種設置。隨著對標準的進一步修訂,OpenMP 最實用的特性之一就是那一組編譯指示,這一點逐漸明朗。通過明智地使用這些編譯指示,單線程程序不需要向 API 或環境變量求助即可實現多線程。通過 OpenMP 2.0 的最新版本,OpenMP 架構審核委員會(ARB)是提出 OpenMP 規范的委員會的正式名稱,顯然開發人員使用編譯指示而不是 API 作為優先選擇。讓我們來更深入地審視這種方法,從翻新編譯指示開始。
以下關于編譯指示的定義(摘自微軟的文檔)是最清晰的解釋之一:“#pragma 指示為每個編譯器提供了一種方法,能夠提供機器指定和操作系統指定特性,同時保留與 C 和 C++ 語言的整體兼容性。根據定義,編譯指示是機器指定或操作系統指定的,通常所有的編譯器都不同。編譯指示最常用于 C 和 C++ 中,格式如下:#pragma token-string”
編譯指示的主要方面是如果編譯器不能識別指定的編譯指示,則它必須忽略(根據 ANSI C 和 C++ 標準)。因此,將庫指定的編譯指示放入代碼中是安全的,不需要擔心如果采用不同的工具包進行編譯會將代碼破壞。
圖 1 顯示了簡單的 OpenMP 編譯指示行動。
?? ??? ??? ??? ?
01 ?? ?#pragma omp parallel for
02 ?? ?
03 ?? ?for ( i = 0; i < x; i++ )
04 ?? ?
05 ?? ?{
06 ?? ?
07 ?? ?printf ( "Loop number is %d%d%d
08 ?? ?
09 ?? ?",
10 ?? ?
11 ?? ?i, i, i );
12 ?? ? ?
13 ?? ?}
圖 1. 通過簡單的 OpenMP 編譯指示實現循環的線程化
這種編譯指示告訴編譯器:以后的for 循環應該實現多線程化,而且線程應該并行執行。簡單的解釋就是:在編譯器完成的工作與 OpenMP 庫之間,for 循環將使用大量線程來執行。OpenMP 將致力于創建線程、通過在線程間劃分交互作用來實現 for 循環的線程化、以及在 for 循環完成后處理線程。
雖然 OpenMP 不保證推理將創建多少線程,但是它通常選擇等于可用執行管線數量的數量。在標準多處理器環境中,這一數量就是處理器的數量。在采用含超線程(HT)技術的處理器的系統上,管線的數量是處理器數量的兩倍。API 函數或環境變量可用于撤銷默認的線程數量。
OpenMP 將提供大量其它的編譯指示來識別需要進行線程化的代碼塊、在線程中共享的范圍變量或本地化到單獨線程,到同步線程,如何安排任務或循環疊代到線程,等等。因此,最終它將通過線程功能提供中等級別紋理型控制。這種級別的紋理對于許多高性能計算(HPC)應用而言已經足夠,在便攜性和最佳執行能力的前提下,OpenMP 能夠提供比大多數其它選擇更好的選擇,尤其是最大限度減少對于代碼庫的干擾。
哪一種線程模型適合您?
OpenMP 非常方便,因為它不會將軟件鎖定在事先設定的線程數量中。此類鎖定工作給使用低級 API(如 Pthreads 或 Win32)的線程應用提出了一個大問題。當運行在更多處理器可用的平臺上時,使用這些 API 編寫的軟件如何擴充線程的數量?一種方法一直是使用線程池(threading pool),其中在程序啟動時創建一束線程,將工作分配到線程上。然而,這種方法需要相當多的線程指定代碼,而且不能保證能夠隨著可用處理器的數量而合理地進行擴充。通過 OpenMP,不需要指定數量。
OpenMP 的編譯指示還有另一項重要優勢:通過禁用 OpenMP 支持,代碼可用作為單一線程應用進行編譯。當調試程序時,以這樣的方式編譯代碼擁有巨大優勢。如果沒有這種選擇,開發人員會經常發現很難說明復雜的代碼是否能夠正確工作,因為線程問題或因為與線程無關的設計錯誤。
如果開發人員需要精細紋理的控制,則他們可以使用 OpenMP 的線程 API。其中包括一小組函數,分為以下三個領域:查詢執行環境的線程資源并設置當前的線程數量;設置、管理并釋放鎖來解決線程之間的資源訪問;和一個小型的定時接口。使用這種 API 讓人失望,因為它會取走純編譯指令方法提供的優勢。在這個級別上,OpenMP API 是 Pthreads 提供的功能的一個小子集。這兩個 API 都具有便攜性,但是 Pthreads 能提供更大范圍的原函數(primitive function),從而對線程化操作提供精細紋理的控制。因此,在必須單獨管理線程的應用中,Pthreads 或本地的線程化 API(如 Windows 上的 Win32)將是更加自然的選擇。
為了運行 OpenMP,開發人員必須促使編譯器支持標準。在 Linux 和 Windows 上,面向 C/C++ 和 Fortran 的英特爾? 編譯器支持 OpenMP。在 UNIX 平臺上,SGI、Sun、惠普和 IBM 都提供兼容 OpenMP 的編譯器。開放源代碼版本通過 Omni OpenMP Compiler 項目提供,網址為http://www.hpcs.cs.tsukuba.ac.jp/omni-openmp/*。
因此,如果您正在為高性能計算(HPC)編寫 UNIX 或 Linux 應用,則應該關注 Pthreads 和 OpenMP。您可能會發現 OpenMP 是一款不錯的解決方案。
資源
Dave Butenhof,《POSIX 線程編程》 (Addison-Wesley, 1997年)。
Rich Gerber 和 Andrew Binstock,《超線程技術編程》(英特爾出版社,2004 年)。
Bil Lewis,《多線程編程教育》,
http://www.lambdacs.com/*
Pthreads Win32, http://sources.redhat.com/pthreads-win32/*
開始使用 OpenMP*
OpenMP* 高級編程
英特爾? 線程處理工具和 OpenMP*
總結
以上是生活随笔為你收集整理的高性能计算的线程模型:Pthreads 还是 OpenMP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python魔术方法abstract_p
- 下一篇: java 多线程日志_多线程 打印的日志