使用 UNIX System V IPC 機(jī)制共享應(yīng)用程序數(shù)據(jù)
引言
Unix 內(nèi)核管理的進(jìn)程自主地操作,從而產(chǎn)生更穩(wěn)定的系統(tǒng)。然而,每個開發(fā)人員最終都會遇到這樣的情況,即其中一組進(jìn)程需要與另一組進(jìn)程通信,也許是為了交換數(shù)據(jù)或發(fā)送命令。這種通信稱為進(jìn)程間通信(Inter-Process Communication,IPC)。System V (SysV) UNIX 規(guī)范描述了以下三種 IPC 機(jī)制,它們統(tǒng)稱為 SysV IPC:
消息隊列
信號量
共享內(nèi)存
此外,進(jìn)程還可以通過其他機(jī)制通信,例如:
讀、寫和鎖定文件
信號
套接字
管道
FIFO(先進(jìn)先出)
這后一組機(jī)制一般也稱為 IPC。由于其簡單性和有效性,本文將集中于 SysV IPC 方法。
了解 SysV 模型
三種 SysV IPC 方法具有類似的語法,盡管它們具有不同的用途。一般情況下,它們執(zhí)行以下操作:
確定要用于 ftok(3) 的正確 IPC 密鑰。
分別使用 msgget(2)、semget(2) 或 shmget(2) 獲得用于消息隊列、信號量或共享內(nèi)存的特定于 IPC 的標(biāo)識符,這些標(biāo)識符與 IPC 密鑰相關(guān)聯(lián)。
使用 msgctl(2)、semctl(2) 或 shmctl(2) 修改 IPC 實(shí)例的屬性。
利用特定的 IPC 實(shí)例。
最后,使用 msgctl(2)、semctl(2) 或 shmctl(2) 和 IPC_RMID 標(biāo)志銷毀 IPC 實(shí)例。
每個 IPC 實(shí)例都被賦予一個標(biāo)識符,以將它與系統(tǒng)上存在的其他 IPC 實(shí)例區(qū)分開來。例如,兩個不同的應(yīng)用程序可能分別決定使用共享內(nèi)存段,因此系統(tǒng)范圍的 IPC ID 將區(qū)分這兩個實(shí)例。雖然可能不是那么明顯,但是第一個挑戰(zhàn)就是弄清如何分發(fā)這樣的信息:即如何在沒有準(zhǔn)備某種 IPC 機(jī)制的情況下附加到一個公共 IPC 實(shí)例。
ftok 庫調(diào)用使用某個給定文件中的索引節(jié)點(diǎn)信息和一個唯一標(biāo)識符來得出一個密鑰,只要該文件存在并且該標(biāo)識符為常量,此密鑰就保持相同。因此,兩個進(jìn)程可以使用它們的配置文件和編譯時常量來得出相同的 IPC 密鑰。常量的存在允許同一個應(yīng)用程序通過改變常量來創(chuàng)建 IPC 機(jī)制的多個實(shí)例。
在一組進(jìn)程獨(dú)立得出各自的 IPC 密鑰之后,它們必須使用某個 get 系統(tǒng)調(diào)用來獲得與該特定 IPC 實(shí)例關(guān)聯(lián)的特定標(biāo)識符。各個 get 調(diào)用全都需要 IPC 密鑰和一組標(biāo)志,以及一些信號量和共享內(nèi)存大小信息。由于 Unix 是多用戶系統(tǒng),標(biāo)志將包括熟悉的八進(jìn)制形式的文件權(quán)限(因此 666 意味著任何人都可以執(zhí)行讀和寫)。如果還設(shè)置了 IPC_CREAT 標(biāo)志,則會在 IPC 實(shí)例不存在時創(chuàng)建該實(shí)例。如果沒有設(shè)置 IPC_CREAT 標(biāo)志并且還未創(chuàng)建 IPC 實(shí)例,則 get 調(diào)用將返回錯誤。
對于能夠自己分發(fā) IPC 實(shí)例標(biāo)識符的應(yīng)用程序,存在一種用于執(zhí)行該任務(wù)的更簡單方法。如果您在調(diào)用 get 以創(chuàng)建 IPC 時使用密鑰 IPC_PRIVATE,則實(shí)例標(biāo)識符將是唯一的。需要附加到該 IPC 的其他進(jìn)程不需要調(diào)用 get,因為它們已經(jīng)擁有該標(biāo)識符。
一旦擁有了標(biāo)識符,應(yīng)用程序就可以任意使用 IPC 實(shí)例。每種 IPC 方法都是不同的,并在它們各自的部分中進(jìn)行處理。
通過隊列傳遞消息
消息隊列提供了一種機(jī)制,使得一個進(jìn)程可以發(fā)送另一個進(jìn)程能夠獲得的消息。在獲得該消息之后,將從隊列中刪除該消息。消息隊列非常獨(dú)特,因為兩個進(jìn)程不必同時存在——一個進(jìn)程可以發(fā)送一個消息并退出,而該消息可以在數(shù)天后才被另一個進(jìn)程獲得。
消息必須由一個長整數(shù)后面跟著消息數(shù)據(jù)組成。清單 1 顯示了 C 語言中的這樣一個結(jié)構(gòu),其中使用了一個 100 字節(jié)的消息。
清單 1. 示例消息的 C 語言定義
struct mq_message {long type; /* The type or destination */char text[100]; /* Data */};
消息接收者使用消息類型。當(dāng)從隊列輪詢消息時,您可以選擇第一個可用的消息,或者可以查找某種特定的消息類型。將要使用的消息類型特定于應(yīng)用程序,從而使得隊列獨(dú)特于其他形式的 IPC,因為內(nèi)核通過讀取 type 字段,從而在一定程度上了解所傳遞的應(yīng)用程序數(shù)據(jù)。
清單 2 顯示了消息隊列的消息提交部分。
清單 2. 向消息隊列提交消息的程序
#include <sys/types.h>#include <sys/msg.h>#include <sys/ipc.h>#include <string.h>#include <stdio.h>int main (void) {key_t ipckey;int mq_id;struct { long type; char text[100]; } mymsg;/* Generate the ipc key */ipckey = ftok("/tmp/foo", 42);printf("My key is %dn", ipckey);/* Set up the message queue */mq_id = msgget(ipckey, IPC_CREAT | 0666);printf("Message identifIEr is %dn", mq_id);/* Send a message */memset(mymsg.text, 0, 100); /* Clear out the space */strcpy(mymsg.text, "Hello, world!");mymsg.type = 1;msgsnd(mq_id, &mymsg, sizeof(mymsg), 0);}
清單 2 中的代碼包括了必要的頭文件,然后定義了將在 main 函數(shù)中使用的變量。第一要務(wù)是使用 /tmp/foo 作為命令文件和使用數(shù)字 42 作為 ID 來確定 IPC 密鑰。出于演示的目的,這里使用 printf(3c) 將密鑰顯示在屏幕上。接下來,該代碼使用 msgget 創(chuàng)建消息隊列。msgget 的第一個參數(shù)是 IPC 密鑰,第二個參數(shù)是一組標(biāo)志。在該示例中,標(biāo)志包括八進(jìn)制權(quán)限(該權(quán)限允許具有 IPC 密鑰的任何人完全使用該 IPC)和 IPC_CREAT 標(biāo)志(此標(biāo)志導(dǎo)致 msgget 創(chuàng)建隊列)。同樣,結(jié)果被打印到屏幕上。
將消息發(fā)送到隊列是非常簡單的。在對消息中的內(nèi)存空間清零之后,將一個熟悉的字符串復(fù)制到緩沖區(qū)的文本部分。將消息類型設(shè)置為 1,然后調(diào)用 msgsnd。msgsnd 預(yù)期接受的參數(shù)為隊列 ID、一個指向數(shù)據(jù)的指針和數(shù)據(jù)的大小,以及一個指示是否阻塞該調(diào)用的標(biāo)志。如果該標(biāo)志為 IPC_NOWAIT,則即使隊列已滿,該調(diào)用也會返回。如果該標(biāo)志為 0,則調(diào)用將阻塞,直至隊列上的空間被釋放、隊列被刪除或應(yīng)用程序收到某個信號。
該過程的客戶端行為與此類似。清單 3 顯示了檢索服務(wù)器發(fā)送的消息的代碼。
清單 3. 用于從隊列檢索消息的代碼
#include <sys/types.h>#include <sys/msg.h>#include <sys/ipc.h>#include <string.h>#include <stdio.h>int main (void) {key_t ipckey;int mq_id;struct { long type; char text[100]; } mymsg;int received;/* Generate the ipc key */ipckey = ftok("/tmp/foo", 42);printf("My key is %dn", ipckey);/* Set up the message queue */mq_id = msgget(ipckey, 0);printf("Message identifIEr is %dn", mq_id);received = msgrcv(mq_id, &mymsg, sizeof(mymsg), 0, 0);printf("%s (%d)n", mymsg.text, received);}
獲得 IPC 密鑰和消息隊列標(biāo)識符的過程與服務(wù)器的代碼類似。對 msgget 的調(diào)用不指定任何標(biāo)志,因為服務(wù)器已經(jīng)創(chuàng)建了隊列。如果應(yīng)用程序的設(shè)計允許客戶端在服務(wù)器之前啟動,則客戶端和服務(wù)器都必須指定權(quán)限和 IPC_CREAT 標(biāo)志,以便其中首先啟動的應(yīng)用程序創(chuàng)建隊列。
然后 mq_clIEnt.c 調(diào)用 msgrcv 以從隊列提取消息。前三個參數(shù)指定消息隊列標(biāo)識符、指向?qū)⒌膬?nèi)存空間的指針和緩沖區(qū)的大小。第四個參數(shù)是類型參數(shù),它允許您選擇所要獲得的消息:
如果類型為 0,則返回隊列中的第一個消息。
如果類型為正整數(shù),則返回隊列中的第一個該類型的消息。
如果類型為負(fù)整數(shù),則返回隊列中具有最小值的第一個消息,且該最小值小于或等于指定類型的絕對值。例如,如果要將 2 然后再將 1 添加到隊列,則使用類型 -2 調(diào)用 msgrcv 將返回 1,因為它最小,盡管它是隊列中的第二個消息。
傳遞給 msgrcv 的第五個參數(shù)同樣是阻塞標(biāo)志。清單 4 顯示了實(shí)際操作中的客戶端和服務(wù)器。
清單 4. 客戶端和服務(wù)器代碼的輸出
sunbox$ ./mq_serverMy key is 704654099Message identifier is 2sunbox$ ./mq_clientMy key is 704654099Message identifier is 2Hello, world! (104)
客戶端和服務(wù)器的輸出表明,它們得出了相同的 IPC 密鑰,因為它們都引用同一個文件和標(biāo)識符。服務(wù)器創(chuàng)建了 IPC 實(shí)例,內(nèi)核為該實(shí)例分配了值 2,并且客戶端應(yīng)用程序知道這一點(diǎn)。這樣,客戶端從消息隊列提取回“Hello, world!就沒什么奇怪的了。
此示例顯示了最簡單的情況。消息隊列對于短期進(jìn)程是有用的,例如將工作提交給重負(fù)荷后端應(yīng)用程序(例如某個批處理應(yīng)用程序)的 Web 事務(wù)。客戶端也可以是服務(wù)器,并且多個應(yīng)用程序可以向隊列提交消息。消息類型字段允許應(yīng)用程序?qū)⑾l(fā)送給特定的讀取器。
使用信號量鎖定資源
進(jìn)程之間的通信不需要涉及到發(fā)送大量的數(shù)據(jù)。實(shí)際上,單個位可能就足以指示某個進(jìn)程在使用某個資源。請考慮兩個需要訪問某個硬件部分的進(jìn)程,但是一次只有一個進(jìn)程能夠使用該硬件。每個進(jìn)程就包含引用計數(shù)器的點(diǎn)達(dá)成一致。如果一個進(jìn)程讀取該計數(shù)器并看到其值為 1,則它就知道另一個進(jìn)程正在使用該硬件。如果該計數(shù)器的值為 0,則該進(jìn)程就可以自由使用該硬件資源,前提是在該硬件操作期間將計數(shù)器設(shè)置為 1 并在結(jié)束操作時將其重置為 0。
此場景存在兩個問題:第一個問題不過就是設(shè)置共享計數(shù)器并就其位置達(dá)成一致,再沒有比這麻煩的了。第二個問題是鎖定硬件資源所需要的獲取和設(shè)置操作不是原子的。如果一個進(jìn)程在讀取計數(shù)器時,其值為 0,但是在它還沒有機(jī)會將計數(shù)器設(shè)置為 1 之前,另一個進(jìn)程已搶先讀取了該計數(shù)器,則第二個進(jìn)程就能夠讀取和設(shè)置計數(shù)器。兩個進(jìn)程都會認(rèn)為它們可以使用該硬件。沒有辦法知道另一個或其他進(jìn)程是否會設(shè)置該計數(shù)器。這稱為爭用條件。信號量通過提供一個公共應(yīng)用程序接口,以及通過實(shí)現(xiàn)原子測試和設(shè)置操作,從而同時解決了這兩個問題。
信號量的 SysV 實(shí)現(xiàn)比上述解決方案更通用。首先,信號量的值不需要是 0 或 1;它可以是 0 或任何正數(shù)。其次,可以執(zhí)行一系列信號量操作,與用于 msgrcv 的 type 參數(shù)非常類似。這些操作作為一個指令集提供給內(nèi)核,并且這些指令要么全部運(yùn)行,要么一個也不會運(yùn)行。內(nèi)核要求將這些指令放在一個名為 sembuf 的結(jié)構(gòu)中,該結(jié)構(gòu)具有以下成員(按順序):
sem_num:描述正在操作該集合中的哪一個信號量。
sem_op:一個有符號整數(shù),其中包含要執(zhí)行的指令或測試。
sem_flg:熟悉的 IPC_NOWAIT 標(biāo)志(它指示測試應(yīng)該立即返回還是阻塞直至通過)和 SEM_UNDO(它在進(jìn)程提前退出時導(dǎo)致撤銷該信號量操作)的組合。
sem_op 是放置許多配置的地方:
如果 sem_op 為 0,則測試 sem_num 以確定它是否為 0。如果 sem_num 為 0,則運(yùn)行下一個測試。如果 sem_num 不為 0,則在未設(shè)置 IPC_NOWAIT 時,操作將阻塞直至信號量變?yōu)?0,而在設(shè)置了 IPC_NOWAIT 時,則跳過其他測試。
如果 sem_op 是某個正數(shù),則將信號量的值加上 sem_op 的值。
如果 sem_op 是一個負(fù)整數(shù),并且信號量的值大于或等于 sem_op 的絕對值,則從信號量的值減去該絕對值。
如果 sem_op 是一個負(fù)整數(shù),并且信號量的值小于 sem_op 的絕對值,則在 IPC_NOWAIT 為 true 時立即停止測試的執(zhí)行,而在該值為 false 時則阻塞,直至信號量的值變得大于 sem_op 的絕對值。
清單 5 中的示例闡明了信號量的使用,其中研究了一個可同時運(yùn)行多次的程序,但是該程序確保一次只有一個進(jìn)程處于關(guān)鍵部分。其中使用了簡單情況下的信號量;當(dāng)信號量的值為 0 時釋放資源。
清單 5. 使用信號量來保護(hù)關(guān)鍵部分
#include <sys/types.h>#include <sys/sem.h>#include <sys/ipc.h>#include <string.h> /* For strerror(3c) */#include <errno.h> /* For errno */#include <unistd.h> /* rand(3c) */#include <stdio.h>int main (int argc, char **argv) {key_t ipckey;int semid;struct sembuf sem[2]; /* sembuf defined in sys/sem.h *//* Generate the ipc key */ipckey = ftok("/tmp/foo", 42);/* Set up the semaphore set. 4 == READ, 2 == ALTER */semid = semget(ipckey, 1, 0666 | IPC_CREAT);if (semid < 0) {printf("Error - %sn", strerror(errno));_exit(1);}/* These never change so leave them outside the loop */sem[0].sem_num = 0;sem[1].sem_num = 0;sem[0].sem_flg = SEM_UNDO; /* Release semaphore on exit */sem[1].sem_flg = SEM_UNDO; /* Release semaphore on exit */while(1) { /* loop forever */printf("[%s] Waiting for the semaphore to be releasedn", argv[1]);/* Set up two semaphore operations */sem[0].sem_op = 0; /* Wait for zero */sem[1].sem_op = 1; /* Add 1 to lock it*/semop(semid, sem, 2);printf("[%s] I have the semaphoren", argv[1]);sleep(rand() % 3); /* Critical section, sleep for 0-2 seconds */sem[0].sem_op = -1; /* Decrement to unlock */semop(semid, sem, 1);printf("[%s] Released semaphoren", argv[1]);sleep(rand() % 3); /* Sleep 0-2 seconds */}}
清單 5 的開頭與消息隊列示例的開頭相同。其中 msgget 在第二個參數(shù)中指定消息隊列的大小,semget 指定信號量集(Semaphore Set) 的大小。信號量集是一組共享一個公共 IPC 實(shí)例的信號量。該集合中的信號量數(shù)量無法更改。如果已經(jīng)創(chuàng)建了信號量集,則 semget 的第二個參數(shù)實(shí)際上被忽略。如果 semget 返回一個指示失敗的負(fù)整數(shù),則打印原因,并退出程序。
在主 while 循環(huán)之前,對 sem_num 和 sem_flg 進(jìn)行了初始化,因為它們在整個示例中保持一致。此外還指定了 SEM_UNDO,以便在信號量擁有者未能釋放該信號量就已退出的情況下,不會鎖定所有其他應(yīng)用程序。
該循環(huán)中還打印了一個狀態(tài)消息,以指示應(yīng)用程序已開始等待信號量。此輸出附帶第一個命令行參數(shù)作為前綴,以將它與其他實(shí)例區(qū)分開來。在進(jìn)入關(guān)鍵部分之前,應(yīng)用程序鎖定了信號量。此示例中指定了兩個信號量指令。第一個為 0,意味著應(yīng)用程序?qū)⒌却敝列盘柫恐祷謴?fù)為 0。第二個為 1,意味著在信號量恢復(fù)為零之后,將向該信號量加 1。應(yīng)用程序調(diào)用 semop 以運(yùn)行指令,并向其傳遞信號量 ID、數(shù)據(jù)結(jié)構(gòu)的地址和要使用的 sembuf 指令數(shù)量。
在 semop 返回以后,應(yīng)用程序知道它已經(jīng)鎖定了信號量,并打印一個消息以指示這一點(diǎn)。然后關(guān)鍵部分將會運(yùn)行,在此例中是隨機(jī)地暫停幾秒。最后,使用 semop 值 -1 來運(yùn)行單個 sembuf 命令,從而釋放信號量,這實(shí)際上是從信號量減去 1,并將其值恢復(fù)為 0。隨后打印更多的調(diào)試輸出,應(yīng)用程序隨機(jī)暫停,然后繼續(xù)執(zhí)行。清單 6 顯示了此應(yīng)用程序的兩個實(shí)例的輸出。
清單 6. 兩個使用信號量來保護(hù)關(guān)鍵部分的程序
sunbox$ ./sem_example a & ./sem_example b &[a] Waiting for the semaphore to be released[a] I have the semaphore[b] Waiting for the semaphore to be released[a] Released semaphore[b] I have the semaphore[a] Waiting for the semaphore to be released[b] Released semaphore[a] I have the semaphore[a] Released semaphore[a] Waiting for the semaphore to be released[a] I have the semaphore
清單 6 顯示了運(yùn)行的示例的兩個實(shí)例,這兩個實(shí)例分別具有名稱 a 和 b。首先,a 獲得信號量,在 a 擁有該信號量的同時,b 嘗試獲得一個鎖。一旦釋放了信號量,b 即獲得鎖。現(xiàn)在情況顛倒過來,變?yōu)榈却?b 完成。最后,a 在信號量被釋放后再次獲得該信號量,因為 b 沒有等待。
關(guān)于信號量,要注意的最后一個事項在于,它們被稱為建議鎖(Advisory Lock)。這意味著信號量本身并不阻止兩個進(jìn)程同時使用同一個資源;相反,它們旨在建議任何進(jìn)程自愿詢問該資源是否正在使用。
共享內(nèi)存空間
共享內(nèi)存也許是最強(qiáng)大的 SysV IPC 方法,并且此方法最容易實(shí)現(xiàn)。顧名思義,共享內(nèi)存是在兩個進(jìn)程之間共享一個內(nèi)存塊。清單 7 顯示了一個程序,該程序調(diào)用 fork(2) 來將自身劃分為一個父進(jìn)程和一個子進(jìn)程,兩個進(jìn)程之間使用一個共享內(nèi)存段進(jìn)行通信。
清單 7. 演示共享內(nèi)存用法的程序
#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <unistd.h>#include <string.h>#include <errno.h>int main(void) {pid_t pid;int *shared; /* pointer to the shm */int shmid;shmid = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0666);if (fork() == 0) { /* Child *//* Attach to shared memory and print the pointer */shared = shmat(shmid, (void *) 0, 0);printf("Child pointer %pn", shared);*shared=1;printf("Child value=%dn", *shared);sleep(2);printf("Child value=%dn", *shared);} else { /* Parent *//* Attach to shared memory and print the pointer */shared = shmat(shmid, (void *) 0, 0);printf("Parent pointer %pn", shared);printf("Parent value=%dn", *shared);sleep(1);*shared=42;printf("Parent value=%dn", *shared);sleep(5);shmctl(shmid, IPC_RMID, 0);}}
您現(xiàn)在應(yīng)該已經(jīng)熟悉傳遞給 shmget 的參數(shù)了:密鑰、大小和標(biāo)志。此示例中的共享內(nèi)存大小是單個整數(shù)。清單 7 與前一個示例的不同之處在于它對 IPC 密鑰使用了 IPC_PRIVATE。當(dāng)使用了 IPC_PRIVATE 時,將保證創(chuàng)建一個唯一的 IPC ID,并且預(yù)期應(yīng)用程序?qū)⒆约悍职l(fā)該 ID。在此示例中,父進(jìn)程和子進(jìn)程都知道 shmid,因為它們分別是對方的副本。fork 系統(tǒng)調(diào)用創(chuàng)建當(dāng)前進(jìn)程的第二個副本,稱為子進(jìn)程,此進(jìn)程幾乎與父進(jìn)程完全相同。兩個進(jìn)程的執(zhí)行都在 fork 之后恢復(fù)。返回值將用于確定當(dāng)前進(jìn)程是父進(jìn)程還是子進(jìn)程。
父進(jìn)程和子進(jìn)程看起來相似。首先,shmat 系統(tǒng)調(diào)用被用于獲得指向共享內(nèi)存段的指針。shmat 需要共享內(nèi)存 ID、一個指針和某些標(biāo)志。該指針用于請求特定的內(nèi)存地址。通過傳遞 0,內(nèi)核可以隨心所欲地選擇任何內(nèi)存地址。標(biāo)志大部分是特定于供應(yīng)商的,不過 SHM_RDONLY 是一個公共標(biāo)志,用于指示不寫入的段。如清單 7 所示,shmat 的常見用法是讓內(nèi)核決定一切。
shmat 返回一個指向共享內(nèi)存段的指針,此示例出于調(diào)試目的而將其打印到了屏幕上。然后每個進(jìn)程依次修改該共享內(nèi)存段,并打印出值。最后,父進(jìn)程使用 shmctl(2) 來刪除共享內(nèi)存段。清單 8 顯示了此程序的輸出。
清單 8. 共享內(nèi)存示例的輸出
sunbox$ ./shared_memoryChild pointer ff390000Child value=1Parent pointer ff380000Parent value=1Parent value=42Child value=42
您可以從輸出中看到相同內(nèi)存空間的共享。起初,共享內(nèi)存中的值為 1,這是由子進(jìn)程設(shè)置并由父進(jìn)程讀取的。然后父進(jìn)程將該值設(shè)置為 42,并由子進(jìn)程讀取。請注意,父進(jìn)程和子進(jìn)程擁有指向共享內(nèi)存段的不同指針地址,盡管它們是在訪問相同的物理內(nèi)存。在使用物理地址時,這會導(dǎo)致某些數(shù)據(jù)結(jié)構(gòu)出現(xiàn)問題,例如鏈表,因此當(dāng)您在共享內(nèi)存中構(gòu)建復(fù)雜結(jié)構(gòu)時,可以使用相對尋址。
此示例依賴在一個進(jìn)程向共享內(nèi)存寫入時,另一個進(jìn)程暫停。在實(shí)際應(yīng)用程序中,這是不切實(shí)際的,因此,如果您的應(yīng)用程序可能潛在地?fù)碛卸鄠€向相同內(nèi)存位置執(zhí)行寫入的進(jìn)程,可以考慮使用信號量來鎖定該區(qū)域。
結(jié)束語
Unix 提供了若干種用于 IPC 的方法。SysV IPC 方法是消息隊列、信號量和共享內(nèi)存。消息隊列允許一個應(yīng)用程序提交消息,其他應(yīng)用程序可以在以后獲得該消息,甚至是在發(fā)送應(yīng)用程序已結(jié)束之后。信號量確保多個應(yīng)用程序可以鎖定資源并避免爭用條件。共享內(nèi)存允許多個應(yīng)用程序共享一個公共內(nèi)存段,從而提供了一種傳遞和共享大量數(shù)據(jù)的快速方法。您還可以將這些方法結(jié)合起來使用。例如,您可以使用信號量來控制對共享內(nèi)存段的訪問。
IPC 方法對應(yīng)用程序開發(fā)人員非常有用,因為它們提供了應(yīng)用程序之間的標(biāo)準(zhǔn)通信方法,并且是跨不同 UNIX 風(fēng)格可移植的。當(dāng)您下次發(fā)現(xiàn)自己需要鎖定資源或在進(jìn)程之間共享數(shù)據(jù)時,可以試驗一下 SysV IPC 機(jī)制。
