天天看點

作業系統核心原理-3.程序原理(下):程序通信

作業系統核心原理-3.程式原理(下):程式通信

程序作為人類的發明,自然也免不了脫離人類的習性,也有通信的需求。如果程序之間不進行任何通信,那麼程序所能完成的任務就要大打折扣。人類的通信方式無外乎對白(通過聲音溝通)、打手勢、寫信、發電報、擁抱等方法。同理,程序也可以通過同樣的方式來進行通信。本篇我們就來看看程序的這些互動方式。

  程序作為人類的發明,自然也免不了脫離人類的習性,也有通信的需求。如果程序之間不進行任何通信,那麼程序所能完成的任務就要大打折扣。人類的通信方式無外乎對白(通過聲音溝通)、打手勢、寫信、發電報、擁抱等方法。同理,程序也可以通過同樣的方式來進行通信。本篇我們就來看看程序的這些互動方式。

一、程序對白:管道、套接字

  人們最常用的通信手段就是對白,一方發出聲音,另一方接收聲音。而聲音的傳遞需要通過一些媒體,例如:空氣(face to face)、線纜(有線電話)等。類似的,程序對白就是一個程序發出某種資料資訊,另外一方接收資料資訊,而這些資料資訊通過一片共享的存儲空間進行傳遞。

1.1 管道

作業系統核心原理-3.程式原理(下):程式通信

  一個程序向存儲空間的一端寫入資訊,另一個程序存儲空間的另外一端讀取資訊,這個就是管道。就像兩個人對白的媒介是空氣也可以是線纜一樣,管道所占的空間既可以是記憶體也可以是磁盤。

  要建立一個管道,一個程序隻需要調用管道建立的系統調用即可,該系統調用所做的事情就是在某種存儲媒體上劃出一片空間,賦給其中一個程序寫的權利,另一個程序讀的權利即可。

  例如在Linux下,我們通過Shell指令輸入兩個指令,中間通過符号“|”來建立兩個指令之間的管道:

$ sort < file1 | grep zou      

  上面一個指令表示:對file1的内容首先進行排序,排序完成後的結果将作為grep的輸入,在結果裡面找出所有包括字元串zou的文本行。也就是說,在兩個任務“排序“(sort)和”查找”(grep)之間建立了一個管道,資料從sort流向了grep。

1.2 套接字

作業系統核心原理-3.程式原理(下):程式通信

  套接字(Socket)的功能非常強大,可以支援不同層面、不同應用、跨網絡的通信。使用套接字進行通信需要雙方均建立一個套接字,其中一方作為伺服器方,另外一方作為客戶方。伺服器方必須首先建立一個服務區套接字,然後在該套接字上進行監聽,等待遠方的連接配接請求。客戶方也要建立一個套接字,然後向伺服器方發送連接配接請求。伺服器套接字在受到連接配接請求之後,将在伺服器方機器上建立一個客戶套接字,與遠方的客戶方套接字形成點到點的通信通道。之後,客戶方和伺服器友善可以直接通過類似于send和recv的指令在這個建立的套接字管道上進行交流了。

  例如,在C#中我們可以輕松地建立一個伺服器方的Socket:

// 建立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)必須首先在通信的程序間建立連接配接(管道或套接字),這需要消耗系統資源;

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

  (3)由于建立連接配接需要消耗時間,一旦建立就應該盡可能多的通信,如果通信資訊量很小,則就是“殺雞用牛刀”了;

二、程序電報與旗語:信号與信号量

2.1 電報:信号

作業系統核心原理-3.程式原理(下):程式通信

  信号類似于我們生活中的電報,如果你想給某人發一封電報,就拟好電文,然後将封包和收報人的資訊都交給電報公司。電報公司則将電報發送到收報人所在地的郵局,并通知收報人來取電報。其中,發封包時無需收報人實作知道,也無需進行任何協調。如果對方選擇不對信号做出響應,則将被OS終止運作。

  在計算機中,信号就是一個核心對象或者是一個核心資料結構。發送方将該資料結構的内容填好,并指明該信号的目标程序後,發出特定的軟體中斷(這就是一個發電報的操作)。OS接收到特定的中斷請求後,知道是有程序要發送信号,于是到特定的核心資料結構裡查找信号接收方,并進行通知。接到通知的程序則對信号進行相應處理。

2.2 旗語:信号量

作業系統核心原理-3.程式原理(下):程式通信

  信号量來源于鐵路的運作:在一條單軌鐵路上,任何時候隻允許有一列火車行駛在該鐵路上,而管理這條鐵路的系統就是信号量。任何一列火車必須等到表明該鐵路可以行駛的信号後才能進入軌道。當列車進入後,需要将信号改為禁止狀态進入來防止别的列車同時進入。而當列車駛出單軌後,則需要将信号變回允許進入狀态,這很像以前的旗語。當然,通過聯想到我們實際開發中經常用的鎖,這就更容易了解了。

  在計算機中,信号量實際上就是一個簡單整數。一個程序在信号變為0或1的情況下推進,并将信号變為1或0來防止别的程序同時推進。當該程序完成任務後,則将信号再改為0或1,進而允許其他程序執行。進而我們也可以看出,信号量已經不隻是一種通信機制,更是一種同步機制。

三、程序擁抱:共享記憶體

  前面通過對話、發電報、旗語已經滿足了多種通信需要,但是當兩個程序要共享大量資料時就沒法十分滿足需求。就如同兩個墜入愛河的騷年,它們互相喜歡并想要在一起同居(共享大量資料),這時打電話、發電報、握手對話就顯得不夠了。這時候,它們需要的就是擁抱,隻有緊緊擁抱才能盡可能地共享,feeling so good!

作業系統核心原理-3.程式原理(下):程式通信

3.1 共享記憶體

作業系統核心原理-3.程式原理(下):程式通信

  程序的擁抱就是共享記憶體,兩個程序共同擁有同一片記憶體。對于這片記憶體中的任何内容,二者均可以通路。要使用共享記憶體進行通信,程序A首先需要建立一片記憶體空間作為通信用,而其他程序B則将片記憶體映射到自己的(虛拟)位址空間。這樣,程序A讀寫自己位址空間中對應共享記憶體的區域時,就是在和程序B進行通信。

3.2 不足之處

  (1)使用共享記憶體機制通信的兩個程序必須在同一台實體機上;

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

四、信件發送:消息隊列

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

作業系統核心原理-3.程式原理(下):程式通信

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

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

  (2)消息隊列可以同時支援多個程序,多個程序可以讀寫消息隊列;即所謂的多對多,而管道是點對點;

  (3)消息隊列隻在記憶體中實作,而管道還可以在磁盤上實作;

參考資料

作業系統核心原理-3.程式原理(下):程式通信

鄒恒明,《作業系統之哲學原理》,機械工業出版社

作者:周旭龍

出處:http://edisonchou.cnblogs.com

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連結。

繼續閱讀