System V 與 POSIX 初步認識
當我們在 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系統調用。