【送本】計算機領域神書《深入理解計算機系統》

作者:Randal E. Bryant,David R. O'Hallaron
來源:華章計算機(hzbook_jsj)
[文末送書福利]
 

文末包郵送兩本《深入理解計算機系統》第三版。

《深入理解計算機系統》(簡稱CS:APP)的主要讀者是計算機科學家、計算機工程師,以及那些想通過學習計算機系統的內在運作而能夠寫出更好程序的人。
 
我們的目的是解釋所有計算機系統的本質概念,並向你展示這些概念是如何實實在在地影響應用程序的正確性、性能和實用性的。其他的系統類書籍都是從構建者的角度來寫的,講述如何實現硬件或系統軟件,包括操作系統、編譯器和網絡接口。而 本書是從程序員的角度來寫的,講述應用程序員如何能夠利用系統知識來編寫出更好的程序 。當然,學習一個計算機系統應該做些什麼,是學習如何構建一個計算機系統的很好的出發點,所以,對於希望繼續學習系統軟硬件實現的人來說,本書也是一本很有價值的介紹性讀物。大多數系統書籍還傾向於重點關注系統的某一個方面,比如:硬件架構、操作系統、編譯器或者網絡。本書則以程序員的視角統一覆蓋了上述所有方面的內容。
 

如果你研究和領會了這本書裏的概念,你將開始成爲極少數的“牛人”,這些“牛人”知道事情是如何運作的,也知道當事情出現故障時如何修復。你寫的程序將能夠更好地利用操作系統和系統軟件提供的功能,對各種操作條件和運行時參數都能正確操作,運行起來更快,並能避免出現使程序容易受到網絡攻擊的缺陷。同時,你也要做好更深入探究的準備,研究像編譯器、計算機體系結構、操作系統、嵌入式系統、網絡互聯和網絡安全這樣的高級題目。

 
0 1
讀者應具備的背景知識


本書的重點是執行x86-64機器代碼的系統。對英特爾及其競爭對手而言,x86-64是他們自1978年起,以8086微處理器爲代表,不斷進化的最新成果。按照英特爾微處理器產品線的命名規則,這類微處理器俗稱爲“x86”。隨着半導體技術的演進,單芯片上集成了更多的晶體管,這些處理器的計算能力和內存容量有了很大的增長。在這個過程中,它們從處理16位字,發展到引入IA32處理器處理32位字,再到最近的x86-64處理64位字。
 
我們考慮的是這些機器如何在Linux操作系統上運行C語言程序。Linux是衆多繼承自最初由貝爾實驗室開發的Unix的操作系統中的一種。這類操作系統的其他成員包括SolarisFreeBSDMacOS X。近年來,由於Posix和標準Unix規範的標準化努力,這些操作系統保持了高度兼容性。因此,本書內容幾乎直接適用於這些“類Unix”操作系統。
 
文中包含大量已在Linux系統上編譯和運行過的程序示例。我們假設你能訪問一臺這樣的機器,並且能夠登錄,做一些諸如切換目錄之類的簡單操作。如果你的計算機運行的是Microsoft Windows系統,我們建議你選擇安裝一個虛擬機環境(例如VirtualBox或者VMWare),以便爲一種操作系統(客戶OS)編寫的程序能在另一種系統(宿主OS)上運行。
 
我們還假設你對C和C++有一定的瞭解。如果你以前只有Java經驗,那麼你需要付出更多的努力來完成這種轉換,不過我們也會幫助你。JavaC有相似的語法和控制語句。不過,有一些C語言的特性(特別是指針、顯式的動態內存分配和格式化I/O)在Java中都是沒有的。所幸的是,C是一個較小的語言,在Brian KernighanDennis Ritchie經典的“K&R”文獻中得到了清晰優美的描述。無論你的編程背景如何,都應該考慮將K&R作爲個人系統藏書的一部分。如果你只有使用解釋性語言的經驗,如PythonRubyPerl,那麼在使用本書之前,需要花費一些時間來學習C

本書的前幾章揭示了C語言程序和它們相對應的機器語言程序之間的交互作用。機器語言示例都是用運行在x86-64處理器上的GNU GCC編譯器生成的。我們不需要你以前有任何硬件、機器語言或是彙編語言編程的經驗。
 

建議


給C語言初學者 關於C編程語言的建議


爲了幫助C語言編程背景薄弱(或全無背景)的讀者,我們在書中加入了這樣一些專門的註釋來突出C中一些特別重要的特性。我們假設你熟悉C++或Java。


0 2
如何閱讀此書



從程序員的角度學習計算機系統是如何工作的會非常有趣,主要是因爲你可以主動地做這件事情。無論何時你學到一些新的東西,都可以馬上試驗並且直接看到運行結果。事實上,我們相信學習系統的唯一方法就是做(do)系統,即在真正的系統上解決具體的問題,或是編寫和運行程序。
 
這個主題觀念貫穿全書。當引入一個新概念時,將會有一個或多個練習題緊隨其後,你應該馬上做一做來檢驗你的理解。這些練習題的解答在每章的末尾。當你閱讀時,嘗試自己來解答每個問題,然後再查閱答案,看自己的答案是否正確。除第1章外,每章後面都有難度不同的家庭作業。對每個家庭作業題,我們標註了難度級別:

只需要幾分鐘。幾乎或完全不需要編程。
可能需要將近20分鐘。通常包括編寫和測試一些代碼。(許多都源自我們在考試中出的題目。)
需要很大的努力,也許是1~2個小時。一般包括編寫和測試大量的代碼。
一個實驗作業,需要將近10個小時。

文中每段代碼示例都是由經過GCC編譯的C程序直接生成並在Linux系統上進行了測試,沒有任何人爲的改動。當然,你的系統上GCC的版本可能不同,或者根本就是另外一種編譯器,那麼可能生成不一樣的機器代碼,但是整體行爲表現應該是一樣的。所有的源程序代碼都可以從csapp.cs.cmu.edu上的CS:APP主頁上獲取。在本書中,源程序的文件名列在兩條水平線的右邊,水平線之間是格式化的代碼。比如,圖1中的程序能在code/intro/目錄下的hello.c文件中找到。當遇到這些示例程序時,我們鼓勵你在自己的系統上試着運行它們。
 

爲了避免本書體積過大、內容過多,我們添加了許多網絡 旁註 (Web aside),包括一些對本書主要內容的補充資料。本書中用CHAP:TOP這樣的標記形式來引用這些旁註,這裏CHAP是該章主題的縮寫編碼,而TOP是涉及的話題的縮寫編碼。例如,網絡旁註DATA:BOOL包含對第2章中數據表示裏面有關布爾代數內容的補充資料;而網絡旁註ARCH:VLOG包含的是用Verilog硬件描述語言進行處理器設計的資料,是對第4章中處理器設計部分的補充。所有的網絡旁註都可以從CS:APP的主頁上獲取。
 

旁註


什麼是旁註?


在整本書中,你將會遇到很多以這種形式出現的旁註。旁註是附加說明,能使你對當前討論的主題多一些瞭解。旁註可以有很多用處。一些是小的歷史故事。例如,C語言、Linux和Internet是從何而來的?有些旁註則是用來澄清學生們經常感到疑惑的問題。例如,高速緩存的行、組和塊有什麼區別?還有些旁註給出了一些現實世界的例子。例如,一個浮點錯誤怎麼毀掉了法國的一枚火箭,或是給出市面上出售的一個磁盤驅動器的幾何和運行參數。最後,還有一些旁註僅僅就是一些有趣的內容,例如,什麼是“hoinky”?

0 3
本書概述



本書由12章組成,旨在闡述計算機系統的核心概念。內容概述如下:

1章:計算機系統漫遊。 這一章通過研究“helloworld”這個簡單程序的生命週期,介紹計算機系統的主要概念和主題。

2章:信息的表示和處理。 我們講述了計算機的算術運算,重點描述了會對程序員有影響的無符號數和數的補碼錶示的特性。我們考慮數字是如何表示的,以及由此確定對於一個給定的字長,其可能編碼值的範圍。我們探討有符號和無符號數字之間類型轉換的效果,還闡述算術運算的數學特性。菜鳥級程序員經常很驚奇地瞭解到(用補碼錶示的)兩個正數的和或者積可能爲負。另一方面,補碼的算術運算滿足很多整數運算的代數特性,因此,編譯器可以很安全地把一個常量乘法轉化爲一系列的移位和加法。我們用C語言的位級操作來說明布爾代數的原理和應用。我們從兩個方面講述了IEEE標準的浮點格式:一是如何用它來表示數值,一是浮點運算的數學屬性。

對計算機的算術運算有深刻的理解是寫出可靠程序的關鍵。比如,程序員和編譯器不能用表達式(x-y<0)來替代(x<y),因爲前者可能會產生溢出。甚至也不能用表達式(-y<-x)來替代,因爲在補碼錶示中負數和正數的範圍是不對稱的。算術溢出是造成程序錯誤和安全漏洞的一個常見根源,然而很少有書從程序員的角度來講述計算機算術運算的特性。

3章:程序的機器級表示。 我們教讀者如何閱讀由C編譯器生成的x86-64機器代碼。我們說明爲不同控制結構(比如條件、循環和開關語句)生成的基本指令模式。我們還講述過程的實現,包括棧分配、寄存器使用慣例和參數傳遞。我們討論不同數據結構(如結構、聯合和數組)的分配和訪問方式。我們還說明實現整數和浮點數算術運算的指令。我們還以分析程序在機器級的樣子作爲途徑,來理解常見的代碼安全漏洞(例如緩衝區溢出),以及理解程序員、編譯器和操作系統可以採取的減輕這些威脅的措施。學習本章的概念能夠幫助讀者成爲更好的程序員,因爲你們懂得程序在機器上是如何表示的。另外一個好處就在於讀者會對指針有非常全面而具體的理解。

4章:處理器體系結構。 這一章講述基本的組合和時序邏輯元素,並展示這些元素如何在數據通路中組合到一起,來執行x86-64指令集的一個稱爲“Y86-64”的簡化子集。我們從設計單時鐘週期數據通路開始。這個設計概念上非常簡單,但是運行速度不會太快。然後我們引入流水線的思想,將處理一條指令所需要的不同步驟實現爲獨立的階段。這個設計中,在任何時刻,每個階段都可以處理不同的指令。我們的五階段處理器流水線更加實用。本章中處理器設計的控制邏輯是用一種稱爲HCL的簡單硬件描述語言來描述的。用HCL寫的硬件設計能夠編譯和鏈接到本書提供的模擬器中,還可以根據這些設計生成Verilog描述,它適合合成到實際可以運行的硬件上去。

5章:優化程序性能。 在這一章裏,我們介紹了許多提高代碼性能的技術,主要思想就是讓程序員通過使編譯器能夠生成更有效的機器代碼來學習編寫C代碼。我們一開始介紹的是減少程序需要做的工作的變換,這些是在任何機器上寫任何程序時都應該遵循的。然後講的是增加生成的機器代碼中指令級並行度的變換,因而提高了程序在現代“超標量”處理器上的性能。爲了解釋這些變換行之有效的原理,我們介紹了一個簡單的操作模型,它描述了現代亂序處理器是如何工作的,然後給出瞭如何根據一個程序的圖形化表示中的關鍵路徑來測量一個程序可能的性能。你會驚訝於對C代碼做一些簡單的變換能給程序帶來多大的速度提升。

6章:存儲器層次結構。 對應用程序員來說,存儲器系統是計算機系統中最直接可見的部分之一。到目前爲止,讀者一直認同這樣一個存儲器系統概念模型,認爲它是一個有一致訪問時間的線性數組。實際上,存儲器系統是一個由不同容量、造價和訪問時間的存儲設備組成的層次結構。我們講述不同類型的隨機存取存儲器(RAM)和只讀存儲器(ROM),以及磁盤和固態硬盤  (直譯應爲固態驅動器,但固態硬盤一詞已經被大家接受,所以沿用。——譯者注) 的幾何形狀和組織構造。我們描述這些存儲設備是如何放置在層次結構中的,講述訪問局部性是如何使這種層次結構成爲可能的。我們通過一個獨特的觀點使這些理論具體化,那就是將存儲器系統視爲一個“存儲器山”,山脊是時間局部性,而斜坡是空間局部性。最後,我們向讀者闡述如何通過改善程序的時間局部性和空間局部性來提高應用程序的性能。

7章:鏈接。 本章講述靜態和動態鏈接,包括的概念有可重定位的和可執行的目標文件、符號解析、重定位、靜態庫、共享目標庫、位置無關代碼,以及庫打樁。大多數講述系統的書中都不講鏈接,我們要講述它是出於以下原因。第一,程序員遇到的最令人迷惑的問題中,有一些和鏈接時的小故障有關,尤其是對那些大型軟件包來說。第二,鏈接器生成的目標文件是與一些像加載、虛擬內存和內存映射這樣的概念相關的。

8章:異常控制流。 在本書的這個部分,我們通過介紹異常控制流(即除正常分支和過程調用以外的控制流的變化)的一般概念,打破單一程序的模型。我們給出存在於系統所有層次的異常控制流的例子,從底層的硬件異常和中斷,到併發進程的上下文切換,到由於接收Linux信號引起的控制流突變,到C語言中破壞棧原則的非本地跳轉。

在這一章,我們介紹進程的基本概念,進程是對一個正在執行的程序的一種抽象。 讀者會學習進程是如何工作的,以及如何在應用程序中創建和操縱進程。 我們會展示應用程序員如何通過Linux系統調用來使用多個進程。 學完本章之後,讀者就能夠編寫帶作業控制的 Linux shell 了。 同時,這裏也會向讀者初步展示程序的併發執行會引起不確定的行爲。

9章:虛擬內存。 我們講述虛擬內存系統是希望讀者對它是如何工作的以及它的特性有所瞭解。我們想讓讀者瞭解爲什麼不同的併發進程各自都有一個完全相同的地址範圍,能共享某些頁,而又獨佔另外一些頁。我們還講了一些管理和操縱虛擬內存的問題。特別地,我們討論了存儲分配操作,就像標準庫的mallocfree操作。闡述這些內容是出於下面幾個目的。它加強了這樣一個概念,那就是虛擬內存空間只是一個字節數組,程序可以把它劃分成不同的存儲單元。它可以幫助讀者理解當程序包含存儲泄漏和非法指針引用等內存引用錯誤時的後果。最後,許多應用程序員編寫自己的優化了的存儲分配操作來滿足應用程序的需要和特性。這一章比其他任何一章都更能展現將計算機系統中的硬件和軟件結合起來闡述的優點。而傳統的計算機體系結構和操作系統書籍都只講述虛擬內存的某一方面。

10章:系統級I/O 我們講述Unix I/O的基本概念,例如文件和描述符。我們描述如何共享文件,I/O重定向是如何工作的,還有如何訪問文件的元數據。我們還開發了一個健壯的帶緩衝區的I/O包,可以正確處理一種稱爲short counts的奇特行爲,也就是庫函數只讀取一部分的輸入數據。我們闡述C的標準I/O庫,以及它與Linux I/O的關係,重點談到標準I/O的侷限性,這些侷限性使之不適合網絡編程。總的來說,本章的主題是後面兩章——網絡和併發編程的基礎。

11章:網絡編程。 對編程而言,網絡是非常有趣的I/O設備,它將許多我們前面文中學習的概念(比如進程、信號、字節順序、內存映射和動態內存分配)聯繫在一起。網絡程序還爲下一章的主題——併發,提供了一個很令人信服的上下文。本章只是網絡編程的一個很小的部分,使讀者能夠編寫一個簡單的Web服務器。我們還講述位於所有網絡程序底層的客戶端服務器模型。我們展現了一個程序員對Internet的觀點,並且教讀者如何用套接字接口來編寫Internet客戶端和服務器。最後,我們介紹超文本傳輸協議(HTTP),並開發了一個簡單的迭代式Web服務器。

12章:併發編程。 這一章以Internet服務器設計爲例介紹了併發編程。我們比較對照了三種編寫併發程序的基本機制(進程、I/O多路複用和線程),並且展示如何用它們來建造併發Internet服務器。我們探討了用PV信號量操作來實現同步、線程安全和可重入、競爭條件以及死鎖等的基本原則。對大多數服務器應用來說,寫併發代碼都是很關鍵的。我們還講述了線程級編程的使用方法,用這種方法來表達應用程序中的並行性,使得程序在多核處理器上能執行得更快。使用所有的核解決同一個計算問題需要很小心謹慎地協調併發線程,既要保證正確性,又要爭取獲得高性能。

0 4
本版新增內容



本書的第1版於2003年出版,第2版在2011年出版。考慮到計算機技術發展如此迅速,這本書的內容還算是保持得很好。事實證明Intel x86的機器上運行Linux(以及相關操作系統),加上採用C語言編程,是一種能夠涵蓋當今許多系統的組合。然而,硬件技術、編譯器和程序庫接口的變化,以及很多教師教授這些內容的經驗,都促使我們做了大量的修改。

第2版以來的最大整體變化是,我們的介紹從以IA32x86-64爲基礎,轉變爲完全以x86-64爲基礎。這種重心的轉移影響了很多章節的內容。下面列出一些明顯的變化:
  • 1。我們將第5章對Amdahl定理的討論移到了本章。

  • 2。讀者和評論家的反饋是一致的,本章的一些內容有點令人不知所措。因此,我們澄清了一些知識點,用更加數學的方式來描述,使得這些內容更容易理解。這使得讀者能先略過數學細節,獲得高層次的總體概念,然後回過頭來進行更細緻深入的閱讀。

  • 第3章我們將之前基於IA32x86-64的表現形式轉換爲完全基於x86-64,還更新了近期版本GCC產生的代碼。其結果是大量的重寫工作,包括修改了一些概念提出的順序。同時,我們還首次介紹了對處理浮點數據的程序的機器級支持。由於歷史原因,我們給出了一個網絡旁註描述IA32機器碼。

  • 4。我們將之前基於32位架構的處理器設計修改爲支持64位字和操作的設計。

  • 5。我們更新了內容以反映最近幾代x86-64處理器的性能。通過引入更多的功能單元和更復雜的控制邏輯,我們開發的基於程序數據流表示的程序性能模型,其性能預測變得比之前更加可靠。

  • 6。我們對內容進行了更新,以反映更多的近期技術。

  • 7。針對x86-64,我們重寫了本章,擴充了關於用GOTPLT創建位置無關代碼的討論,新增了一節描述更加強大的鏈接技術,比如庫打樁。

  • 8。我們增加了對信號處理程序更細緻的描述,包括異步信號安全的函數,編寫信號處理程序的具體指導原則,以及用sigsuspend等待處理程序。

  • 9。本章變化不大。

  • 10。我們新增了一節說明文件和文件的層次結構,除此之外,本章的變化不大。

  • 11。我們介紹了採用最新getaddrinfogetnameinfo函數的、與協議無關和線程安全的網絡編程,取代過時的、不可重入的gethostbynamegethostbyaddr函數。

  • 12。我們擴充了利用線程級並行性使得程序在多核機器上更快運行的內容。

此外,我們還增加和修改了很多練習題和家庭作業。
 
0 5
本書的起源



本書起源於1998年秋季,我們在卡內基梅隆(CMU)大學開設的一門編號爲15-213的介紹性課程:計算機系統導論(Introduction to Computer SystemICS)。從那以後,每學期都開設了ICS這門課程,每學期有超過400名學生上課,這些學生從本科二年級到碩士研究生都有,所學專業也很廣泛。這門課程是卡內基梅隆大學計算機科學系(CS)以及電子和計算機工程系(ECE)所有本科生的必修課,也是CSECE大多數高級系統課程的先行必修課。
 
ICS這門課程的宗旨是用一種不同的方式向學生介紹計算機。因爲,我們的學生中幾乎沒有人有機會親自去構造一個計算機系統。另一方面,大多數學生,甚至包括所有的計算機科學家和計算機工程師,也需要日常使用計算機和編寫計算機程序。所以我們決定從程序員的角度來講解系統,並採用這樣的原則過濾要講述的內容:我們只討論那些影響用戶級C語言程序的性能、正確性或實用性的主題。
 
比如,我們排除了諸如硬件加法器和總線設計這樣的主題。雖然我們談及了機器語言,但是重點並不在於如何手工編寫彙編語言,而是關注C語言編譯器是如何將C語言的結構翻譯成機器代碼的,包括編譯器是如何翻譯指針、循環、過程調用以及開關(switch)語句的。更進一步地,我們將更廣泛和全盤地看待系統,包括硬件和系統軟件,涵蓋了包括鏈接、加載、進程、信號、性能優化、虛擬內存、I/O以及網絡與併發編程等在內的主題。
 
這種做法使得我們講授ICS課程的方式對學生來講既實用、具體,還能動手操作,同時也非常能調動學生的積極性。很快地,我們收到來自學生和教職工非常熱烈而積極的反響,我們意識到卡內基梅隆大學以外的其他人也可以從我們的方法中獲益。因此,這本書從ICS課程的筆記中應運而生了,而現在我們對它做了修改,使之能夠反映科學技術以及計算機系統實現中的變化和進步。
 
通過本書的多個版本和多種語言譯本,ICS和許多相似課程已經成爲世界範圍內數百所高校的計算機科學和計算機工程課程的一部分。
 
本文摘編自《深入理解計算機系統(原書第3版)》,經出版方授權發佈。


作者 [美蘭德爾 E.布萊恩特(Randal E. Bryant
大衛 R. 奧哈拉倫(David R. O'Hallaron) 
譯者 龔奕利、賀蓮

被譽爲 價值超過等重量黃金的無價資源寶庫 理解計算機系統首書目, 十餘萬程序員的共同選擇。

本書是一本將計算機軟件和硬件理論結合講述的經典教程,內容覆蓋計算機導論、體系結構和處理器設計等多門課程。卡內基-梅隆大學、北京大學、上海交大等國內外衆多知名高校選用指定教材。本書的最大優點是爲程序員描述計算機系統的實現細節,通過描述程序是如何映射到系統上,以及程序是如何執行的,使讀者更好地理解程序的行爲,以及造成效率低下的原因。
 
如何使用本書從程序員的角度來學習計算機系統是如何工作的會非常有趣。最理想的學習方法是在真正的系統上解決具體的問題,或是編寫和運行程序。這個主題觀念貫穿本書始終。因此我們建議你用如下方式學習這本書:
  • 習一個新概念時,你應該立刻做一做緊隨其後的一個或多個練習題來檢驗你的理解。這些練習題的解答在每章的末尾。要先嚐試自己來解答每個問題,然後再查閱答案。

  • 每一章後都有一組難度不同的作業題,這些題目需要的時間從十幾分鍾到十幾個小時,但建議你嘗試完成這些作業題,完成之後你會發現對系統的理解更加深入。

  • 本書中有豐富的代碼示例,鼓勵你在系統上運行這些示例的源代碼。

  • 向老師或他人請教和交流是很好的學習方式。
現在正好趕上開學季網店促銷,限時5折中!好書趕緊入手!

送書說明

關注”前端自習課“或添加我的微信,回覆 計算機 獲取抽獎二維碼,抽 2 本。

本次送書活動的開獎日期爲:2021-03-13 17:00,祝大家好運。

注意上述送書活動的中獎者請於 3 天內聯繫我兌獎,逾期無效再次感謝 華章圖書 對本次活動的大力支持🌹。

本文分享自微信公衆號 - 前端自習課(FE-study)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章