linux下的進程通訊

來源:互聯網
上載者:User

作者:王姍姍,華清遠見嵌入式學院講師。

  Linux下的進程通訊手段基本上是從Unix平台上的進程通訊手段繼承而來的。而對Unix發展做出重大貢獻的兩大主力AT&T的貝爾實驗室及BSD(加州大學伯克利分校的伯克利軟體發布中心)在處理序間通訊方面的側重點有所不同。前者對Unix早期的處理序間通訊手段進行了系統的改進和擴充,形成了“system
V IPC”,通訊進程局限在單個電腦內;後者則跳過了該限制,形成了基於套介面(socket)的處理序間通訊機制。Linux則把兩者繼承了下來,示:

  其中,最初Unix IPC包括:管道、FIFO、訊號;System V IPC包括:SySTem V訊息佇列、System
V號誌、System V共用記憶體區;POSIx IPC包括:
Posix訊息佇列、Posix號誌、Posix共用記憶體區。有兩點需要簡單說明一下:

  1)由於Unix版本的多樣性,電子電氣工程協會(IEEE)開發了一個獨立的Unix標準,這個新的ANSI Unix標準被稱為電腦環境的可移植性作業系統介面(PSOIX)。現有大部分Unix和流行版本都是遵循POSIX標準的,而Linux從一開始就遵循POSIX標準;

  2)BSD並不是沒有涉足單機內的處理序間通訊(socket本身就可以用於單機內的處理序間通訊)。事實上,很多Unix版本的單機IPC留有BSD的痕迹,如4.4BSD支援的匿名記憶體映射、4.3+BSD對可靠訊號語義的實現等等。

  linux下處理序間通訊的幾種主要手段簡介:

  1.管道

  管道是處理序間通訊中最古老的方式,它包括無名管道和有名管道兩種,前者可用於具有親緣關係進程間的通訊,即可用於父進程和子進程間的通訊,後者額克服了管道沒有名字的限制,因此,除具有前者所具有的功能外,它還允許無親緣關係進程間的通訊,即可用於運行於同一台機器上的任意兩個進程間的通訊。

  無名管道由pipe()函數建立:

  #include <unistd.h>

  int pipe(int filedis[2]);

  參數filedis返回兩個檔案描述符:filedes[0]為讀而開啟,filedes[1]為寫而開啟。filedes[1]的輸出是filedes[0]的輸入。

  在Linux系統下,有名管道可由兩種方式建立:命令列方式mknod系統調用和函數mkfifo。下面的兩種途徑都在目前的目錄下產生了一個名為myfifo的有名管道:

  方式一:mkfifo("myfifo","rw");

  方式二:mknod myfifo p

  產生了有名管道後,就可以使用一般的檔案I/O函數如open、close、read、write等來對它進行操作。

  2.訊息佇列

  訊息佇列是訊息的連結資料表,包括Posix訊息佇列system V訊息佇列。訊息佇列用於運行於同一台機器上的處理序間通訊,它和管道很相似,有足夠許可權的進程可以向隊列中添加訊息,被賦予讀許可權的進程則可以讀走隊列中的訊息。訊息佇列克服了訊號承載資訊量少,管道只能承載無格式位元組流以及緩衝區大小受限等缺點。 我們可以用流管道或者套介面的方式來取代它。

  3.共用記憶體

  共用記憶體是運行在同一台機器上的處理序間通訊最快的方式,因為資料不需要在不同的進程間複製。通常由一個進程建立一塊共用記憶體區,其餘進程對這塊記憶體區進行讀寫。共用記憶體往往與其它通訊機制,如訊號量結合使用,來達到進程間的同步及互斥。

  首先要用的函數是shmget,它獲得一個共用儲存標識符。

  #include <sys/types.h>

  #include <sys/ipc.h>

  #include <sys/shm.h>

  int shmget(key_t key, int size, int flag);

  這個函數有點類似大家熟悉的malloc函數,系統按照請求分配size大小的記憶體用作共用記憶體。Linux系統核心中每個IPC結構都有的一個非負整數的標識符,這樣對一個訊息佇列發送訊息時只要引用標識符就可以了。這個標識符是核心由IPC結構的關鍵字得到的,這個關鍵字,就是上面第一個函數的key。資料類型key_t是在標頭檔sys/types.h中定義的,它是一個長整形的資料。在我們後面的章節中,還會碰到這個關鍵字。

  當共用記憶體建立後,其餘進程可以調用shmat()將其串連到自身的地址空間中。

  void *shmat(int shmid, void *addr, int flag);

  shmid為shmget函數返回的共用儲存標識符,addr和flag參數決定了以什麼方式來確定串連的地址,函數的傳回值即是該進程資料區段所串連的實際地址,進程可以對此進程進行讀寫操作。

  使用共用儲存來實現處理序間通訊的注意點是對資料存取的同步,必須確保當一個進程去讀取資料時,它所想要的資料已經寫好了。通常,訊號量被要來實現對共用儲存資料存取的同步,另外,可以通過使用shmctl函數設定共用儲存記憶體的某些標誌位如SHM_LOCK、SHM_UNLOCK等來實現。

  4。訊號量

  訊號量又稱為號誌,它是用來協調不同進程間的資料對象的,而最主要的應用是前一節的共用記憶體方式的處理序間通訊。本質上,訊號量是一個計數器,它用來記錄對某個資源(如共用記憶體)的存取狀況。一般說來,為了獲得共用資源,進程需要執行下列操作:

  (1)
測試控制該資源的訊號量。

  (2) 若此訊號量的值為正,則允許進行使用該資源。進程將進號量減1。

  (3) 若此訊號量為0,則該資源目前不可用,進程進入睡眠狀態,直至訊號量值大於0,進程被喚醒,轉入步驟(1)。

  (4) 當進程不再使用一個訊號量控制的資源時,訊號量值加1。如果此時有進程正在睡眠等待此訊號量,則喚醒此進程。

  維護訊號量狀態的是Linux核心作業系統而不是使用者進程。我們可以從標頭檔/usr/src/linux/include /linux /sem.h中看到核心用來維護訊號量狀態的各個結構的定義。訊號量是一個資料集合,使用者可以單獨使用這一集合的每個元素。要調用的第一個函數是semget,用以獲得一個訊號量ID。

  #include <sys/types.h>

  #include <sys/ipc.h>

  #include <sys/sem.h>

  int semget(key_t key, int nsems, int flag);

  key是前面講過的IPC結構的關鍵字,它將來決定是建立新的訊號量集合,還是引用一個現有的訊號量集合。nsems是該集合中的訊號量數。如果是建立新集合(一般在伺服器中),則必須指定nsems;如果是引用一個現有的訊號量集合(一般在客戶機中)則將nsems指定為0。

  semctl函數用來對訊號量進行操作。

  int semctl(int semid, int semnum, int cmd, uniON semun arg);

  不同的操作是通過cmd參數來實現的,在標頭檔sem.h中定義了7種不同的操作,實際編程時可以參照使用。

  semop函數自動執行訊號量集合上的運算元組。

  int semop(int semid, struct sembuf semoparray[], size_t nops);

  semoparray是一個指標,它指向一個訊號量運算元組。nops規定該數組中操作的數量。

  下面,我們看一個具體的例子,它建立一個特定的IPC結構的關鍵字和一個訊號量,建立此訊號量的索引,修改索引指向的訊號量的值,最後我們清除訊號量。

  5.套介面

  套介面(socket)編程是實現Linux系統和其他大多數作業系統中處理序間通訊的主要方式之一。我們熟知的WWW服務、FTP服務、TELNET服務等都是基於套介面編程來實現的。除了在異地的電腦進程間以外,套介面同樣適用於本地同一台電腦內部的處理序間通訊。

  “本文由華清遠見http://www.embedu.org/index.htm提供”

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.