天天看點

資訊安全系統設計基礎第十三周學習總結

資訊安全系統設計基礎第十三周學習總結

估算學習時間:共10小時

讀書:4

代碼:3

作業:1

部落格:2

實際學習時間:共8.5小時

讀書:2.5

代碼:3.5

部落格:1.5

耗時估計的公式:Y=X+X/N ,Y=X-X/N

第11章 網絡程式設計614

  1. 網絡應用随處可見。任何時候你浏覽Web、發送Email或者彈出一個X window,你就正在使用一個網絡應用程式。有趣的是,所有的網絡應用都是基于相同的基本程式設計模型有着相似的整體邏輯結構,并且依賴相同的程式設計接口。
  2. 網絡應用依賴于很多在系統研究中已經學習過的概念,例如,程序、信号、位元組器映射以及動态存儲配置設定,都扮演着重要的角色。還有一些新概念要掌握。我們需要了解基本的用戶端-伺服器程式設計模型,以及如何編寫使用網際網路提供的服務的用戶端―伺服器程式。最後,我們将把所有這些概念結合起來,開發一個小的但功能齊全的Web的伺服器,能夠為真實的Web,浏覽器提供靜态和動态的文本和圖形内容。

11.1 用戶端-伺服器程式設計模型614

  1. 每個網絡應用都是基于用戶端-伺服器模型的。采用這個模型,一個應用是由一個伺服器戶端提供某種服務。伺服器管理某種資源,并且通過操作這種資源來為它的用戶端提供某種服務。—個FTP伺服器就管理了一組磁盤檔案,它為用戶端進行它會為用戶端進行存儲和檢索。相似地一個電子郵件伺服器管理了一些檔案,它為用戶端進行讀和更新。
  2. 用戶端-伺服器模型中的基本操作是事務
  3. 事務由四步組成

    1)當一個用戶端需要服務時,它向伺服器發送一個請求,發起一個事務。例如,當Web覽器需要一個檔案時,它就發送一個請求給Web伺服器

    2)伺服器收到請求後,解釋它,并以适當的方式操作它的資源。例如,當Web伺服器收到浏覽器發出的請求後,它就讀一個磁盤檔案

    3)伺服器給用戶端發送一響應,并等待下一個請求。例如,Web伺服器将檔案發送回用戶端;

    4)用戶端收到響應并處理它。例如,當Web浏覽器收到來自伺服器的一頁後,它就在螢幕上顯示此頁。

資訊安全系統設計基礎第十三周學習總結

11.2 網絡615

  1. 用戶端和伺服器通常運作在不同的主機上,并且通過計算機網絡的硬體和軟體資源來通信。網絡是複雜的系統,在這裡我們隻想了解一點皮毛。我們的目标是從程式員的角度給你一個可工作的思考模型。對于一個主機而言,網絡隻是又一種I/O裝置,作為資料源和資料接收方,如圖所示。一個插到I/O總線擴充槽的擴充卡提供了到網絡的實體接口。從網絡上接收到的資料從擴充卡經過I/O和存儲器總線拷貝到存儲器,典型地是通過DMA(譯者注:直接存儲器存取方式)傳送。相似地,資料也能從存儲器拷貝到網絡。
資訊安全系統設計基礎第十三周學習總結
  1. 一個以太網段,包括電纜和集線器;每根電纜都有相同的最大位帶寬;集線器不加分辯地将一個端口上收到的每個位複制到其他所有的端口上。是以,每台主機都能看到每個位。
  2. 每個以太網擴充卡都有—個全球唯一的48位位址,它存儲在這個擴充卡的非易失性存儲器上。每個主機擴充卡都能看到這個幀,但是隻有目的主機實際讀取它。
  3. 橋接以太網 由 電纜和網橋 将多個以太網段連接配接起來,形成的較大的區域網路。連接配接網橋的電纜傳輸速率可以不同(例:網橋與網橋之間1GB/S, 網橋與集線器之間100MB/S)。
  4. 網橋作用:連接配接不同網段。同一網段内A向B傳輸資料時,幀到達網橋輸入端口,網橋将其丢棄,不予轉發。A向另一網段内C傳輸資料時,網橋才将幀拷貝到與相應網段連接配接的端口上。進而節省了網段的帶寬
  5. 協定軟體的基本能力:

    命名機制 為每台主機至少配置設定一個網際網路位址,進而消除不同主機位址格式的差異,是每台主機能被識别。

    傳送機制 不同格式的資料進行封裝,使其具有相同的格式。

  6. 區域網路由集線器和網橋及連接配接的電纜組成。

11.3 全球ip網際網路618

  • 全球IP網際網路是最著名和最成功的網際網路絡實作。從1969年起,它就以這樣或那樣的形式存在了。雖然網際網路的内部體系結構複雜而且不斷變化,但是自從20世紀80年代早期以來,用戶端-伺服器應用的組織就一直保持相當的穩定。下圖展示了一個網際網路用戶端-伺服器應用程式的基本硬體和軟體組織。每台網際網路主機都運作實作TCP/TP協定的軟體,幾乎每個現代計算機系統都支援這個協定。網際網路的用戶端和伺服器混合使用套接字接口函數和Unix I/O函數來進行通信。套接字函數典型地是作為會陷入核心的系統調用來實作的,并調用各種核心模式的TCP/IP函數。
資訊安全系統設計基礎第十三周學習總結

11.3.1 ip位址619

  1. 一個IP位址就是一個32位無符号整數。
  2. 網絡程式将IP位址存放在下圖所示的IP位址結構中。
資訊安全系統設計基礎第十三周學習總結
  1. 因為網際網路主機可以有不同的主機位元組順序,TCP/IP為任意整數資料項定義了統一的網絡位元組順序(大端位元組順序)例如IP位址,它放在標頭中跨過網絡被攜帶。在IP位址結構中存放的位址總是以(大端法)網絡位元組順序存放的,即使主機位元組順序是小端法。Unⅸ提供了下面這樣的函數在網絡和主機位元組順序間實作轉換:
資訊安全系統設計基礎第十三周學習總結

11.3.2 網際網路域名620

  1. 網際網路用戶端和伺服器互相通信時使用的是IP位址。然而,對于人們而言,大整數是很難記住的,是以網際網路也定義了一組更加人性化的域名,以及一種将域名映射到IP位址的機制。域名是一串用句點分隔的單詞(字母、數字和破折号)。
  2. 域名集合形成了一個層次結構,每個域名編碼了它在這個層次中的位置。通過一個示例你将很容易了解這點。下展示了域名層次結構的一部分。層次結構可以表示為一棵樹。樹的節點表示城名,反向到根的路徑形成了域名。子樹稱為子域。層次結構中的第一層是個未命名的根節點。下一層是一組一級域名由非赢利組織(網際網路分酒名字數字協會)定義。常見的第一層域名包括com、edu、gov、org、net,這些域名是由ICANN的各個授權代理按照先到先服務的基礎配置設定的的。一旦一個組織得到了一個二級域名,那麼它就可以在這個子域中建立任何新的域名了。
資訊安全系統設計基礎第十三周學習總結

11.3.3 網際網路連接配接623

  1. 網際網路用戶端和伺服器通過在連接配接上發送和接收位元組流來通信。從連接配接一對程序的意義上而言,連接配接是點對點的。從資料可以同時雙向流動的角度來說,它是全雙工的。并且從(除了一些如粗心的耕鋤機操作員切斷了電纜引起災對性的失敗以外)由源程序發出的位元組流最終被目的程序以它發出的順序收到它的角度來說,它也是可靠的。
  2. 一個套接字是連接配接的一個端點。每個套接字都有相應的套接字位址,是由一個網際網路位址和一個16位的整數端口組成的,用“位址:端口”來表示。當用戶端發起一個連接配接請求時,用戶端套接字位址中的端口是由核心自動配置設定的,稱為臨時端口。然而,伺服器套接字位址中的端口通常是某個知名的端口,是和這個服務相對應的。例如,web伺服器通常使用端口80,電子郵件伺服器使用端口25。

11.4 套接字接口625

  • 向導圖
資訊安全系統設計基礎第十三周學習總結

11.4.1 套接字位址結構625

  • 從Unix核心的角度來看,一個套接字就是通信的一個端點。

11.4.2 socket函數626

  1. Socket函數用戶端和伺服器使用函數來建立一個套接字描述符.
資訊安全系統設計基礎第十三周學習總結
  1. 其中,AF_INET表明我們正在使用網際網路,而SCKET_STREAM表示這個套接字是網際網路連接配接一個端點。Socket傳回的clientfd描述符僅是部分打開的,還不能用于讀寫。如何完成打開套接字的工作,取決于我們是用戶端還是伺服器。

11.4.3 connect函數626

  1. 用戶端通過connect函數來建立和伺服器的連接配接。
資訊安全系統設計基礎第十三周學習總結
  1. connect函數試圖與套接字位址為serv_addr的伺服器建立一個網際網路連接配接,其中addrlen是size of ( sockaddr_in )。Connect函數會阻塞,一直到連接配接成功建立或是發生錯誤如果成功,sockfd描述符現在就準備好可以讀寫了,并且得到的連接配接是由套接字對刻畫的。

11.4.4 open_clientfd函數627

  1. 将socket和connect包裝
資訊安全系統設計基礎第十三周學習總結
  1. open_clientfd的代碼
資訊安全系統設計基礎第十三周學習總結

11.4.5 bind函數628

  • bind函數
資訊安全系統設計基礎第十三周學習總結

11.4.6 listen函數628

  • listen函數将sockfd從一個主動套接字轉化為一個監聽套接字。該套接字可以接受來自用戶端的連接配接請求。backlog參數暗示了核心在開始拒絕連接配接請求之前,該放入隊列中等待的未完成連接配接請求的數量
    資訊安全系統設計基礎第十三周學習總結

11.4.7 open_listenfd函數628

資訊安全系統設計基礎第十三周學習總結

11.4.8 accept函數629

資訊安全系統設計基礎第十三周學習總結

11.4.9 echo用戶端和伺服器的示例630

11.5 web伺服器633

11.5.1 web基礎633

  1. Web用戶端和伺服器之間的互動用的是一個基于文本的應用級協定,叫做HTTP。
  2. HTTP是一個簡單的協定。一個web用戶端(即浏覽器)打開一個到伺服器的網際網路連接配接。浏覽器讀取這些内容,并請求某些内容。伺服器響應所請求的内容,然後關閉連接配接。浏覽器讀取并把它顯示在螢幕内
  3. 主要的差別是Web内容可以用HTML來編寫。一個HTML程式(頁)包含指令(标記)它們告訴浏覽器如何顯示這頁中的各種文本和圖形對象。

11.5.2 web内容633

Web伺服器以兩種不同的方式向用戶端提供内容:

  1. 取一個磁盤檔案,并将它的内容傳回給用戶端。
  2. 運作一個可執行檔案,并将它的輸出傳回給用戶端。

11.5.3 http事務634

  1. http請求
  2. http響應

11.5.4 服務動态内容636

  1. 用戶端如何将程式參數傳遞給伺服器
  2. 伺服器如何将參數傳遞給子程序
  3. 伺服器如何将其他資訊傳遞給子程序
  4. 子程序将它的輸出發送到哪裡

11.6 綜合:tiny web伺服器639

  1. TINY的main程式
  2. doit函數
  3. clienterror函數
  4. read_requestthdrs函數
  5. parse_uri函數
  6. serve_static函數
  7. serve_dynamic函數

11.7 小結645

  1. 每個網絡應用都是基于用戶端-伺服器模型的。根據這個模型,一個應用是由一個伺服器和一個或多個用戶端組成的。
  2. 用戶端和伺服器通過網際網路這個全球網絡來通信。從
  3. 用戶端和伺服器通過使用套接字接口建立連接配接。一個套接字是連接配接的一個端點,連接配接是以檔案描述符的形式提供給應用程式的。套接字接口提供了打開和關閉套接字描述符的函數。用戶端和伺服器通過讀寫這些描述符來實作彼此間的通信。
  4. Web伺服器使用HTTP協定和它們的用戶端(例如浏覽器)彼此通信。浏覽器向伺服器請求靜态或者動态的内容。對靜态内容的請求是通過從伺服器磁盤取得檔案并把它傳回給用戶端來服務的。對動态内容的請求是通過在伺服器上一個子程序的上下文中運作一個程式并将它的輸出傳回給用戶端來服務的。CGI标準提供了一組規則,來管理用戶端如何将程式參數傳遞給伺服器,伺服器如何将這些參數以及其他資訊傳遞給子程序,以及子程序如何将它的輸出發送回用戶端。
  5. 隻用幾百行C代碼就能實作一個簡單但是有功效的web小伺服器,它既可以提供靜态内容,也可以提供動态内容。

第12章 并發程式設計648

到目前為止,我們主要将并發看做是一種作業系統核心用來運作多個應用程式的機制。但是,并發不僅僅局限于核心。它也可以在應用程式中扮演重要角色。例如,我們已經看到Unix信号處理程式如何允許應用響應異步事件,例如使用者鍵入。或者程式通路虛拟存儲器的個未定義的區域.應用級并發在其他情況下也是很有用的,例如:

1.通路慢速I/O裝置:當一個應用正在等待來自慢速I/O裝置(例如磁盤)的資料到達時,内I/O請求和其他有用的工作來使用并發。
2.與人互動。和計算機互動的人要求計算機有同時執行多個任務的能力,例如,他們在列印個文檔時,可能想要調整一個視窗的大小。現代視窗系統利用并發來提供這種能力,每次使用者請求某種操作(比如通過單擊滑鼠時,一個獨立的并發邏輯流被建立來執行這個操作。
3.通過推遲工作以降低延遲。有時,應用程式能夠通過推遲其他操作和并發地執行它們利用并發來降低某些操作的延遲。比如,一個動态存儲配置設定器可以通過推遲合并.把它放到個運作在較低優先級上的并發“合并”流中在有空閑的CPU周期時充分利用這些空閑周期進而降低單個free操作的延遲
4.服務多個網絡用戶端。我們在第U章中學習的疊代網絡伺服器是不現實的,因為它們次隻能為一個用戶端提供服務。是以一個慢速的用戶端可能會導緻伺服器拒絕為所有其他用戶端服務。對于一個真正的伺服器來說,可能期望它每秒為成百上千的用戶端提供服務,由于一個慢速用戶端導緻拒絕為其他用戶端服務,這是不能接受的一個更好的方法是建立一個并發伺服器,它為每個用戶端建立一個單獨的邏輯流。這就允許伺服器同時為多個用戶端服務并且這也避免了慢速用戶端獨占伺服器。
5.在多核機器上進行并行計算 多核處理器,多核處理器中包含多個CPU。被劃分成并發流的應用程式通常在多核機器上比在單處理器機器上運作理器中包含多個這些流會并行執行,而不是交錯執行
6.現代作業系統提供了三基本的構造并發程式的方法:程序、I/O多路複用、線程。
           

12.1 基于程序的并發程式設計649

  1. 在接受連接配接請求之後,伺服器派生一個子程序,這個子程序獲得伺服器描述符表的完整拷貝。子程序關閉它的拷貝中的監聽描述符3,而父程序關閉它的已連接配接描述符4的拷貝,因為不再需要這些描述符了。這就得到了圖中的狀态,其中子程序正忙于為用戶端提供服務。因為父子程序中的已連接配接描述符都指向同一個檔案表表項,是以父程序關閉它的已連接配接描述符的拷貝是至關重要的。否則,将永遠不會釋放已連接配接描述符4的檔案表條目,而且由此引起的存儲器洩漏将最終消耗盡可用的存儲器,使系統崩潰。
  2. 現在假設在父程序為用戶端1建立了子程序之後,它接受一個新的用戶端2的連接配接請求,并傳回一個新的已連接配接描述符(比如描述符5)如圖所示。然後,父程序又派生另一個子程序,這個子程序用已連接配接描述符5為它的用戶端提供服務,如圖所示。此時,父程序正在等待下一個連接配接請求,而兩個子程序正在形地為它們各自的用戶端提供服務。
資訊安全系統設計基礎第十三周學習總結

12.1.1 基于程序的并發伺服器649

  • 一個基于程序的并發的echo伺服器的代碼,重要說明:

    首先,通常伺服器會運作很長時間,是以我們必須包括一個SIGCHLD處理程式,來回收僵死子程序資源。

    其次,父子程序必須關閉他們的connfd拷貝。

    最後,因為套接字的檔案表表項的引用計數,直到父子程序的connfd都關閉了,到用戶端的連接配接才會終止。

12.1.2 關于程序的優劣651

  • 關于程序的優劣,對于在父、子程序間共享狀态資訊,程序有一個非常清晰的模型:共享檔案表,但是不共享使用者位址空間。程序有獨立的位址控件愛你既是優點又是缺點。由于獨立的位址空間,是以程序不會覆寫另一個程序的虛拟存儲器。但是另一方面程序間通信就比較麻煩,至少開銷很高。

12.2 基于i/o多路複用的并發程式設計651

  1. 比如一個伺服器,它有兩個I/O事件:1)網絡用戶端發起連接配接請求,2)使用者在鍵盤上鍵入指令行。我們先等待那個事件呢?沒有那個選擇是理想的。如果accept中等待連接配接,那麼無法相應輸入指令。如果在read中等待一個輸入指令,我們就不能響應任何連接配接請求(這個前提是一個程序)。
  2. 針對這種困境的一個解決辦法就是I/O多路複用技術。基本思想是:使用select函數,要求核心挂起程序,隻有在一個或者多個I/O事件發生後,才将控制返給應用程式。如圖所示:橫向的方格可以看作是一個n位的描述符向量。現在,我們定義第0位描述是“标準輸入”,第3位描述符是“監聽描述符”。

12.2.1 基于i/o多路複用的并發事件驅動伺服器653

  • I/O多路複用可以用做并發事件驅動程式的基礎,在事件驅動程式中,流是因為某種事件而前進的,一般概念是将邏輯流模型化為狀态機,不嚴格地說,一個狀态機就是一組狀态,輸入事件和轉移,其中轉移就是将狀态和輸入事件映射到狀态,每個轉移都将一個(輸入狀态,輸入事件)對映射到一個輸出狀态,自循環是同一輸入和輸出狀态之間的轉移,通常把狀态機畫成有向圖,其中節點表示狀态,有向弧表示轉移,而弧上的标号表示輸人事件,一個狀态機從某種初始狀态開始執行,每個輸入事件都會引發一個從目前狀态到下一狀态的轉移,對于每個新的用戶端k,基于I/O多路複用的并發伺服器會建立一個新的狀态機S,并将它和已連接配接描述符d聯系起來。

12.2.2 i/o多路複用技術的優劣657

  1. 事件驅動設計的一個優點是,它比基于程序的設計給了程式員更多的對程式行為的控制。例如我們可以設想編寫一個事件驅動的并發伺服器,為某些客戶提供他們需要的服務,而這對于新程序的并發伺服器來說,是很困難的
  2. 另一個優點是,一個基于I/O多路複用的事件驅動器是運作在單一程序上下文中的,是以每個邏輯流都能通路該程序的全部位址空間。這使得在流之間共享資料變得很容易,一個與作為單個程序運作相關的優點是,你可以利用熟悉的調試工具,例如GDB,來調試你的并發伺服器,就像對順序程式那樣。最後,事件驅動設計常常比基于進利的設計要高效得多,因為它們不需要程序上下文切換來排程新的流。
  3. 事件驅動設計的一個明顯的缺點就是編碼複雜,我們的事件驅動的并發伺服器需要的代度是指每個邏輯流每個時間片執行的指令數量。基于事件的設計的另一個重大缺點是它們不能充分利利用多核處理器。

12.3 基于線程的并發程式設計657

  • 每個線程都有自己的線程上下文,包括一個線程ID、棧、棧指針、程式計數器、通用目的寄存器和條件碼。所有的運作在一個程序裡的線程共享該程序的整個虛拟位址空間。由于線程運作在單一程序中,是以共享這個程序虛拟位址空間的整個内容,包括它的代碼、資料、堆、共享庫和打開的檔案。

12.3.1 線程執行模型657

  • 線程執行的模型。線程和程序的執行模型有些相似。每個程序的聲明周期都是一個線程,我們稱之為主線程。但是大家要有意識:線程是對等的,主線程跟其他線程的差別就是它先執行。

12.3.2 posix線程658

  • POSIX線程是在C程式中處理線程的一個标準接口。它最早出現在1995年,而且在大多數Unix系統上都可用。Pthreads定義了大約60個函數,允許程式建立、殺死和回收線程,與對等線程安全地共享資料,還可以通知對等線程系統狀态的變化。

12.3.3 建立線程659

  • 線程通過調用pthread_create函數來建立其他程序。
    資訊安全系統設計基礎第十三周學習總結
    資訊安全系統設計基礎第十三周學習總結

12.3.4 終止線程659

  • 一個線程是以下列方式之一來終止的。
  • 當頂層的線程例程傳回時,線程會隐式地終止
  • 通過調用pthread_exit函數,線程會顯它會等待所有其他對等線程終止,然後再終止式地終止。
  • 某個對等線程調用Unix的e×it函數,該函數終止程序以及所有與該程序相關的線程

12.3.5 回收已終止線程的資源660

資訊安全系統設計基礎第十三周學習總結

12.3.6 分離線程660

資訊安全系統設計基礎第十三周學習總結

12.3.7 初始化線程660

資訊安全系統設計基礎第十三周學習總結

12.3.8 一個基于線程的并發伺服器661

12.4 多線程程式中的共享變量662

  • 全局變量和static 變量 是存儲在資料段,是以,多線程共享之!
  • 由于線程的棧是獨立的,所有線程中的自動變量是獨立的。即使多個線程運作同一段代碼總的自動變量,那麼他們的值也是根據線程的不同而不同。
  • 比如C++中,類屬性不是在使用者棧中的。是以線程共享之!

12.4.1 線程存儲器模型663

  1. 一組并發線程運作在一個程序的上下文中。每個線程都有它自己獨立的線程上下文,包括線程ID、棧、棧指針、程式計數器、條件碼和通用目的寄存器值。每個線程和其他線程一起共享程序上下文的剩餘部分。這包括整個使用者虛拟位址空間,它是由隻讀文本代碼、讀/寫資料、堆以及所有的共享庫代碼和資料區域組成的。線程也共享同樣的打開檔案的集合。
  2. 從實際操作的角度來說,讓一個線程去讀或寫另一個線程的寄存器值是不可能的。另一方面,任何線程都可以通路共享虛拟存儲器的任意位置。如果某個線程修改了一個存儲器位置,那麼其他每個線程最終都能在它讀這個位置時發現這個變化。是以,寄存器是從不共享的,而虛拟存儲器總是共享的。
  3. 各自獨立的線程棧的存儲器模型不是那麼整齊清楚的。這些棧被儲存在虛拟位址空間的棧區域中,并且通常是被相應的線程獨立地通路的。我們說通常而不是總是,是因為不同的線程棧是不對其他線程設防的是以,如果個線程以某種方式得到個指向其他線程棧的指慧:那麼它就可以讀寫這個棧的任何部分。

12.4.2 将變量映射到存儲器663

線程化的C程式中變量根據它們的存儲類型被映射到虛拟存儲器:

  1. 全局變量。全局變量是定義在函數之外的變量,在運作時,虛拟存儲器的讀/寫區域域隻包含每個全局變量的一個執行個體,任何線程都可以引用。例如第5行聲明的全局變量ptr在虛拟存儲器的讀/寫區域中有個運作時執行個體,我們隻用變量名(在這裡就是ptr)來表示這個執行個體。
  2. 本地自動變量,本地自動變量就是定義在函數内部但是沒有static屬性的變量,在運作時,每個線程的棧都包含它自己的所有本地自動變量的執行個體。即使當多個線程執行同一個線程例程時也是如此。例如,有個本地變量tid的執行個體,它儲存在主線程的棧中。我們用tid.m來表示這個執行個體
  3. 本地靜态變量

12.4.3 共享變量664

我們說一個變量V是共享的,當且僅當它的一個執行個體被一個以上的線程引用。例如,示例程式中的變量cnt就是共享的,因為它隻有一個運作時執行個體,并且這個執行個體被兩個對等線程引用在另一方面,myid不是共享的,因為它的兩個執行個體中每一個都隻被一個線程引用。然而,認識到像msgs這樣的本地自動變量也能被共享是很重要的。

12.5 用信号量同步線程664

  • 信号量通常稱之為PV操作,雖然它的思想是将臨界代碼保護起來,達到互斥效果。這裡面作業系統使用到了線程挂起。
  • 将線程i的循環代碼分解成五個部分:
    資訊安全系統設計基礎第十三周學習總結

12.5.1 進度圖667

  • 程序圖将n個并發程序的執行模型化為一條n維笛卡爾空間中的軌迹線。

12.5.2 信号量668

  • 信号量s是具有非負整數值的全局變量,隻能由兩種特殊的操作來處理,這兩種操作稱為P和V
  • P(s):如果s是非零的,那麼P将s減1并且立即傳回。如果s為零,那麼就挂起這個線程,直到s變為非零,而一個y操作會重新開機這個線程。在重新開機之後,P操作将s減1并将控制傳回給調用者
  • V(s):V操作将s加1。如果有任何線程阻塞在P操作等待s變成非零,那麼V操作會重新開機這些線程中的一個,然後該線程将s減1,完成它的P操作,P中的測試和減1操作是不可分割的,也就是說,一旦預測信号量s變為非零,就會将s減1,不能有中斷。V中的加1操作也是不可分割的,也就是加載、加和存儲信号量的過程中沒有中斷。注意,V的定義中沒有定義等待線程被重新啟動的順序。唯—的要求是V必須隻能重新開機一個正在等待的程序。

12.5.3 使用信号量來實作互斥669

  • 信号量提供了一種很友善的方法來確定對共享變量的互斥通路。基本思想是将每個共享變量(或者一組相關的共享變量)與一個信号量聯系起來 。以這種方式來保護共享變量的信号量叫做二進制信号量,因為它的值總是0或者1。以提供互斥為目的的二進制信号量常常也稱為互斥鎖。在一個互斥鎖上執行P操作稱為對互斥鎖加鎖。類似地,執行V操作稱為對互斥鎖解鎖。對一個互斥鎖加了鎖但是還沒有解鎖的線程稱為占用這個互斥鎖。一個被用作一組可用資源的計數器的信号量稱為計數信号量。關鍵思想是這種P和V操作的結合建立了一組狀态,叫做禁止區。因為信号量的不變性,沒有實際可行的軌迹線能夠包含禁止區中的狀态。而且,因為禁止區完全包括了不安全區,是以沒有實際可行的軌迹線能夠接觸不安全區的任何部分。是以,每條實際可行的軌迹線都是安全的,而且不管運作時指令順序是怎樣的,程式都會正确地增加計數器的值。

12.5.4 利用信号量來排程共享資源670

  1. 生産者-消費者問題。
資訊安全系統設計基礎第十三周學習總結
  1. 讀者-寫者問題。

12.5.5 綜合:基于預線程化的并發伺服器674

  • 在如圖所示的并發伺服器中,我們為每一個新用戶端建立了一個新線程這種方法的缺點是我們為每一個新用戶端建立一個新線程,導緻不小的代價。一個基于預線程化的伺服器試圖通過使用如圖所示的生産者-消費者模型來降低這種開銷。伺服器是由一個主線程和一組工作者線程構成的。主線程不斷地接受來自用戶端的連接配接請求,并将得到的連接配接描述符放在一個不限緩沖區中。每一個工作者線程反複地從共享緩沖區中取出描述符,為用戶端服務,然後等待下一個描述符。
    資訊安全系統設計基礎第十三周學習總結

12.6 使用線程提高并行性676

  • 到目前為止,在對并發的研究中,我們都假設并發線程是在單處許多現代機器具有多核處理器。并發程式通常在這樣的機器上運理器系統上執行的。然而,在多個核上并行地排程這些并發線程,而不是在單個核順序地排程,在像繁忙的Web伺服器、資料庫伺服器和大型科學計算代碼這樣的應用中利用這種并行性是至關重要的。

12.7 其他并發問題680

12.7.1 線程安全680

  1. 我們程式設計過程中,盡可能編寫線程安全函數,即一個函數當且僅當被多個并發線程反複調用時,它會一直産生正确的結果。如果做不到這個條件我們稱之為線程不安全函數。下面介紹四類線程不安全函數:

    ●不保護共享變量的函數。解決辦法是PV操作。

    ●保持跨越多個調用的狀态函數。比如使用靜态變量的函數。解決方法是不要使用靜态變量或者使用可讀靜态變量。

    ●傳回指向靜态變量的指針的函數。解決方法是lock-and-copy(枷鎖-拷貝)

    ●調用線程不安全函數的函數

    死鎖。

  2. 由于PV操作不當,可能造成死鎖現象。這在程式中也會出現。

12.7.2 可重入性682

  1. 有一類重要的線程安全函數,叫做可重入函數。其特點在于他們具有這樣一種屬性:當它們被多個線程調用時,不會引用任何共享資料。盡管線程安全和可重入有時會(正确地)被用做同義詞,但是它們之間還是有清晰的技術差别的,值得留意。圖展示了可重入函數、線程安全函數和線程不安全函數之間的集合關系。所有函數的集合被劃分成不相交的線程安全和線程不安全函數集合。可重入函數集合是線程安全函數的一個真子集。
資訊安全系統設計基礎第十三周學習總結
  1. 可重入函數通常要比不可重入的線程安全的函數高效一些,因為它們不需要同步操作。更進一步來說,将第2類線程不安全函數轉化為線程安全函數的唯一方法就是重寫它,使之變為可重入的。

12.7.3 線上程化的程式中使用已存在的庫函數682

資訊安全系統設計基礎第十三周學習總結

12.7.4 競争683

  • 當一個程式的正确性依賴于一個線程要在另一個線程到達y點之前到達它的控制流中的X點時,就會發生競争。通常發生競争是因為程式員假定線程将按照某種特殊的軌迹正确工作忘記了另一條準則規定:線程化的程式必須對任何可行的軌迹線都正确工作。

12.7.5 死鎖685

  1. 信号量引入了一種潛在的令人厭惡的運作時錯誤,叫做死鎖。它指的是一組線程被阻塞了,等待一個永遠也不會為真的條件。進度圖對于了解死鎖是一個無價的工具。
  2. 關于死鎖的重要知識:
  3. 程式員使用P和V操作漏序不當,以至于兩個信号量的禁止區域重疊。如果某個執行軌迹線碰巧到達了死鎖狀态d那麼就不可能有進一步的進展了,因為重疊的禁止區域阻塞了每個合法方向上的進展。換句話說,程式死鎖是因為每個線程在等待一個根本不可能發生的V操作
  4. 重疊的禁止區域引起了一組稱為死鎖區域的狀态。軌迹線可以進入死鎖區域,但是它們不可能離開。
  5. 死鎖是個相當困難的問題,因為它不總是可預測的。一些幸運的執行軌迹線将繞開死鎖區域,而其他的将會陷入這個區域。

12.8 小結687

  1. 一個并發程是由在時間上重疊的一組邏輯流組成的。在這一章中,我們學習了三種不同的應用程式程、I/O多路複用和線程。我們以一個并發網絡伺服器作為貫穿全章的應用程式。
  2. 程序是由核心自動排程的,而且因為它們有各自獨立的虛拟位址空間,是以要實作共享資料,必須要有顯式的IPC機制。事件驅動程式建立它們自己的并發邏輯流,這些邏輯流被模型之間共享資料速度很快而且很容多路複用來顯式地排程這些流。
  3. 無論哪種并發機制,同步對共享資料的并發通路都是一個困難的問題。提出對信号量的P和V操作就是為了幫助解決這個問題。信号量操作可以用來提供對共享資料的互斥通路,也對諸如生産者-消費者程式中有限緩沖區和讀者―寫者系統中的共享對象這樣的資源通路進行排程。
  4. 并發也引入了其他一些困難的問題。被線程調用的函數必須具有一種稱為線程安全的屬性。我們定義了四類線程不安全的函數,以及一些将它們變為線程安全的建議。可重入函數是線程安全函數的一個真子集,它不通路任何共享資料。可重入函數通常比不可重入函數更為有效,因為它們不需要任何同步原語。競争和死鎖是并發程式中出現的另一些困難的問題。當程式員錯誤地假設邏輯流該如何排程時,就會發生競争。當一個流等待一個永遠不會發生的事件時,時,就會産生死鎖。

感悟

  • 第十一章簡單介紹了網絡模型,TCP/IP協定,類Unix系統的socket接口等。
  • 第十二章 并發程式設計簡單介紹了并發程式設計的内容,主要包括:
    1. 程序級别的并發,各子程序擁有不同的虛拟位址空間,需要IPC(InterProcess Communication)機制共享資料,切換開銷大。
    2. I/O複用,事件驅動,單程序運作,共享虛拟位址空間,并發效果不理想。
    3. 線程,介于上述兩種中間,各子線程共享程序的虛拟位址空間,切換開銷較小。
    4. 另外介紹了并發程式設計中通路共享變量的信号量機制,并給出了4類容易引起線程不安全的函數。

參考資料

  1. 教材:第十一、十二章,詳細學習指導:http://group.cnblogs.com/topic/73069.html
  2. 課程資料:https://www.shiyanlou.com/courses/413 實驗十,課程邀請碼:W7FQKW4Y
  3. 教材中代碼運作、思考一下,讀代碼的學習方法:http://www.cnblogs.com/rocedu/p/4837092.html。
  4. 内容總結:http://www.tuicool.com/articles/qAZnea