當我們在 Linux 系統中進行進程間通信時,例如信號量,消息隊列,共用記憶體等方式,會發現有System V以及POSIX兩種類型。今天我們就來簡單介紹下它們。 POSIX: POSIX(Portable Operating System Interface for Computing System ...
當我們在 Linux 系統中進行進程間通信時,例如信號量,消息隊列,共用記憶體等方式,會發現有System V以及POSIX兩種類型。今天我們就來簡單介紹下它們。
POSIX:
POSIX(Portable Operating System Interface for Computing Systems)是由IEEE 和ISO/IEC 開發的一簇標準。該標準是基於現有的UNIX 實踐和經驗,描述了操作系統的調用服務介面,用於保證編製的應用程式可以在源代碼一級上在多種操作系統上移植運行。它是在1980 年早期一個UNIX 用戶組(usr/group)的早期工作的基礎上取得的。該UNIX 用戶組原來試圖將AT&T 的系統V 和Berkeley CSRG的BSD 系統的調用介面之間的區別重新調和集成,從而於1984 年產生了/usr/group 標準。1985 年,IEEE操作系統技術委員會標準小組委員會(TCOS-SS)開始在ANSI 的支持下責成IEEE 標準委員會制定有關程式源代碼可移植性操作系統服務介面正式標準。到了1986 年4 月,IEEE 就制定出了試用標準。第一個正式標準是在1988 年9 月份批准的(IEEE 1003.1-1988),也既以後經常提到的POSIX.1 標準。
System V:
System V, 曾經也被稱為 AT&T System V,是Unix操作系統眾多版本中的一支。它最初由 AT&T 開發,在1983年第一次發佈。一共發行了4個 System V 的主要版本:版本1、2、3 和 4。System V Release 4,或者稱為SVR4,是最成功的版本,成為一些UNIX共同特性的源頭,例如 ”SysV 初始化腳本“ (/etc/init.d),用來控制系統啟動和關閉,System V Interface Definition (SVID) 是一個System V 如何工作的標准定義。
AT&T 出售運行System V的專有硬體,但許多(或許是大多數)客戶在其上運行一個轉售的版本,這個版本基於 AT&T 的實現說明。流行的SysV 衍生版本包括 Dell SVR4 和 Bull SVR4。當今廣泛使用的 System V 版本是 SCO OpenServer,基於 System V Release 3,以及SUN Solaris 和 SCO UnixWare,都基於 System V Release 4。
System V 是 AT&T 的第一個商業UNIX版本(UNIX System III)的加強。傳統上,System V 被看作是兩種UNIX"風味"之一(另一個是 BSD)。然而,隨著一些並不基於這兩者代碼的UNIX實現的出現,例如 Linux 和 QNX, 這一歸納不再準確,但不論如何,像POSIX這樣的標準化努力一直在試圖減少各種實現之間的不同。
與 System V 對象類似,POSIX IPC 對象的屬主、屬主的組以及其他用戶具有讀取和寫入許可權,但是沒有執行許可權。POSIX IPC 對象的屬主無法將對象分配給其他屬主。POSIX IPC 包括以下功能:
1.消息允許進程將已格式化的數據流發送到任意進程。
2.信號量允許進程同步執行。
3.共用記憶體允許進程共用其部分虛擬地址空間。
與 System V IPC 介面不同,POSIX IPC 介面均為多線程安全介面。
由於之前的文章已經介紹過了System V 的 IPC,所以以下只簡單介紹下 POSIX 的 IPC 介面。
POSIX 消息隊列:
API | API 作用 |
---|---|
mqd_t mq_open(const char name, int oflag, mode_t mode, struct mq_attr attr) | 創建命名消息隊列 |
mqd_t mq_close(mqd_t mqdes) | 結束到開放式消息隊列的連接 |
mqd_t mq_unlink(const char *name) | 結束到開放式消息隊列的連接,併在最後一個進程關閉此隊列時將其刪除 |
mqd_t mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio) | 將消息放入隊列 |
ssize_t mq_receive(mqd_t mqdes, char msg_ptr, size_t msg_len, unsigned msg_prio) | 在隊列中接收消息 |
mqd_t mq_notify(mqd_t mqdes, const struct sigevent *notification) | 通知進程或線程消息已存在於隊列中 |
mqd_t mq_getattr(mqd_t mqdes, struct mq_attr attr) 、mqd_t mq_setattr(mqd_t mqdes, struct mq_attr newattr, struct mq_attr *oldattr) | 設置或獲取消息隊列屬性 |
POSIX 信號量:
API | API 作用 |
---|---|
sem_t sem_open(const char name, int oflag, mode_t mode, unsigned int value) | 創建命名信號量 |
int sem_init(sem_t *sem, int pshared, unsigned int value) | 初始化信號量結構 |
int sem_close(sem_t *sem) | 結束到開放式信號量的連接 |
int sem_unlink(const char *name) | 結束到開放式信號量的連接,併在最後一個進程關閉此信號量時將其刪除 |
int sem_getvalue(sem_t sem, int sval) | 將信號量的值複製到指定整數中 |
int sem_wait(sem_t *sem) | 遞減信號量計數,當其他進程擁有信號量時進行阻塞,或者當其他進程擁有信號量時返回錯誤 |
int sem_post(sem_t *sem) | 遞增信號量計數 |
POSIX 共用記憶體:
API | API 作用 |
---|---|
int shm_open(const char *name, int oflag, mode_t mode) | 創建共用記憶體 |
int shm_unlink(const char *name) | 結束到共用記憶體的連接,併在最後一個進程關閉它時將其刪除 |
void mmap(void addr, size_t length, int prot, int flags, int fd, off_t offset) | 映射記憶體 |
記憶體映射機制mmap是POSIX標準的系統調用,有匿名映射和文件映射兩種:
1.匿名映射使用進程的虛擬記憶體空間,它和malloc()類似,實際上有些malloc實現會使用mmap匿名映射分配記憶體,不過匿名映射不是POSIX標準中規定的。
2.文件映射有MAP_PRIVATE和MAP_SHARED兩種。前者使用COW的方式,把文件映射到當前的進程空間,修改操作不會改動源文件。後者直接把文件映射到當前的進程空間,所有的修改會直接反應到文件的page cache,然後由內核自動同步到映射文件上。
相比於IO函數調用,基於文件的mmap的一大優點是把文件映射到進程的地址空間,避免了數據從用戶緩衝區到內核page cache緩衝區的複製過程;當然還有一個優點就是不需要頻繁的read/write系統調用。
總結
POSIX 在無競爭條件下,不需要陷入內核,其實現是非常輕量級的; System V 則不同,無論有無競爭都要執行系統調用,因此性能落了下風。
總體來說,System V IPC存在時間比較老,許多系統都支持,但是介面複雜,並且可能各平臺上實現略有區別,如下圖的結構限制:
而 POSIX 是新標準,如果只是開發的話,我覺得還是POSIX好,因為其語法簡單、使用方便,並且各平臺上實現都一樣。
System V 的缺點可參考下圖(來自 UNIX環境高級編程):