操做系統核心原理-3.進程原理(下):進程通訊

  進程做爲人類的發明,天然也免不了脫離人類的習性,也有通訊的需求。若是進程之間不進行任何通訊,那麼進程所能完成的任務就要大打折扣。人類的通訊方式無外乎對白(經過聲音溝通)、打手勢、寫信、發電報、擁抱等方法。同理,進程也能夠經過一樣的方式來進行通訊。本篇咱們就來看看進程的這些交互方式。安全

1、進程對白:管道、套接字

  人們最經常使用的通訊手段就是對白,一方發出聲音,另外一方接收聲音。而聲音的傳遞須要經過一些介質,例如:空氣(face to face)、線纜(有線電話)等。相似的,進程對白就是一個進程發出某種數據信息,另一方接收數據信息,而這些數據信息經過一片共享的存儲空間進行傳遞。服務器

1.1 管道

  一個進程向存儲空間的一端寫入信息,另外一個進程存儲空間的另一端讀取信息,這個就是管道。就像兩我的對白的媒介是空氣也能夠是線纜同樣,管道所佔的空間既能夠是內存也能夠是磁盤。網絡

  要建立一個管道,一個進程只須要調用管道建立的系統調用便可,該系統調用所作的事情就是在某種存儲介質上劃出一片空間,賦給其中一個進程寫的權利,另外一個進程讀的權利便可。數據結構

  例如在Linux下,咱們經過Shell命令輸入兩個命令,中間經過符號「|」來建立兩個命令之間的管道:socket

$ sort < file1 | grep zou

  上面一個命令表示:對file1的內容首先進行排序,排序完成後的結果將做爲grep的輸入,在結果裏面找出全部包括字符串zou的文本行。也就是說,在兩個任務「排序「(sort)和」查找」(grep)之間建立了一個管道,數據從sort流向了grep。spa

1.2 套接字

socket

  套接字(Socket)的功能很是強大,能夠支持不一樣層面、不一樣應用、跨網絡的通訊。使用套接字進行通訊須要雙方均建立一個套接字,其中一方做爲服務器方,另一方做爲客戶方。服務器方必須首先建立一個服務區套接字,而後在該套接字上進行監聽,等待遠方的鏈接請求。客戶方也要建立一個套接字,而後向服務器方發送鏈接請求。服務器套接字在受到鏈接請求以後,將在服務器方機器上新建一個客戶套接字,與遠方的客戶方套接字造成點到點的通訊通道。以後,客戶方和服務器方即可以直接經過相似於send和recv的命令在這個建立的套接字管道上進行交流了。操作系統

  例如,在C#中咱們能夠輕鬆地建立一個服務器方的Socket:3d

    // 建立Socket->綁定IP與端口->設置監聽隊列的長度->開啓監聽鏈接
    socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    socketWatch.Bind(new IPEndPoint(IPAddress.Parse(txtIPAddress.Text), int.Parse(txtPort.Text)));
    socketWatch.Listen(10);

1.3 不足之處

  (1)必須首先在通訊的進程間創建鏈接(管道或套接字),這須要消耗系統資源;code

  (2)通訊是自願的,而管道和套接字須要強制雙方進行通訊;對象

  (3)因爲創建鏈接須要消耗時間,一旦創建就應該儘量多的通訊,若是通訊信息量很小,則就是「殺雞用牛刀」了;

2、進程電報與旗語:信號與信號量

2.1 電報:信號

  信號相似於咱們生活中的電報,若是你想給某人發一封電報,就擬好電文,而後將報文和收報人的信息都交給電報公司。電報公司則將電報發送到收報人所在地的郵局,並通知收報人來取電報。其中,發報文時無需收報人實現知道,也無需進行任何協調。若是對方選擇不對信號作出響應,則將被OS終止運行。

  在計算機中,信號就是一個內核對象或者是一個內核數據結構。發送方將該數據結構的內容填好,並指明該信號的目標進程後,發出特定的軟件中斷(這就是一個發電報的操做)。OS接收到特定的中斷請求後,知道是有進程要發送信號,因而到特定的內核數據結構裏查找信號接收方,並進行通知。接到通知的進程則對信號進行相應處理。

2.2 旗語:信號量

  信號量來源於鐵路的運行:在一條單軌鐵路上,任什麼時候候只容許有一列火車行駛在該鐵路上,而管理這條鐵路的系統就是信號量。任何一列火車必須等到代表該鐵路能夠行駛的信號後才能進入軌道。當列車進入後,須要將信號改成禁止狀態進入來防止別的列車同時進入。而當列車駛出單軌後,則須要將信號變回容許進入狀態,這很像之前的旗語。固然,經過聯想到咱們實際開發中常常用的鎖,這就更容易理解了。

  在計算機中,信號量實際上就是一個簡單整數。一個進程在信號變爲0或1的狀況下推動,並將信號變爲1或0來防止別的進程同時推動。當該進程完成任務後,則將信號再改成0或1,從而容許其餘進程執行。從而咱們也能夠看出,信號量已經不僅是一種通訊機制,更是一種同步機制

3、進程擁抱:共享內存

  前面經過對話、發電報、旗語已經知足了多種通訊須要,可是當兩個進程要共享大量數據時就無法十分知足需求。就如同兩個墜入愛河的騷年,它們互相喜歡並想要在一塊兒同居(共享大量數據),這時打電話、發電報、握手對話就顯得不夠了。這時候,它們須要的就是擁抱,只有牢牢擁抱才能儘量地共享,feeling so good!

3.1 共享內存

  進程的擁抱就是共享內存,兩個進程共同擁有同一片內存。對於這片內存中的任何內容,兩者都可以訪問。要使用共享內存進行通訊,進程A首先須要建立一片內存空間做爲通訊用,而其餘進程B則將片內存映射到本身的(虛擬)地址空間。這樣,進程A讀寫本身地址空間中對應共享內存的區域時,就是在和進程B進行通訊。

3.2 不足之處

  (1)使用共享內存機制通訊的兩個進程必須在同一臺物理機上;

  (2)安全性脆弱,假如一個進程有病毒,會很容易傳給另一個進程;

4、信件發送:消息隊列

  消息隊列是一列具備頭和尾的消息排列,新來的消息放在隊列尾部,而讀取消息則從隊列頭部開始,以下圖所示:

  這樣看來,它和管道十分相似,一頭讀,一頭寫?的確,看起來很像管道,但又不是管道:

  (1)消息隊列無固定的讀寫進程,任何進程均可以讀寫;而管道須要指定誰讀和誰寫;

  (2)消息隊列能夠同時支持多個進程,多個進程能夠讀寫消息隊列;即所謂的多對多,而管道是點對點;

  (3)消息隊列只在內存中實現,而管道還能夠在磁盤上實現;

參考資料

鄒恆明,《操做系統之哲學原理》,機械工業出版社

 

相關文章
相關標籤/搜索