標籤:
三種IPC這就是所謂的XSI IPC,每間:
以下分別介紹三種IPC的使用方法。
1、訊息佇列訊息佇列是訊息的連結資料表,具有例如以下函數介面:
- msgget:建立一個新隊列或開啟一個現存的隊列。
- msgsnd:將訊息加入到隊列尾端。
- msgrcv:從隊列中取訊息。
我們能夠自行定義一個表示訊息的結構體,它由類型欄位和實際資料群組成:
struct mest_t { long type; // 訊息類型 char text[512]; // 訊息內容};
有了訊息類型。當我們用msgrcv函數取訊息時,就不一定要以先進先出的順序,而是能夠依據訊息類型取訊息了。以下是一段簡單的測試代碼:
#include <stdio.h>#include <sys/msg.h>#include <sys/types.h>#include <string.h>#include <errno.h> struct mest_t { long type; char text[512];}; int main(void){ pid_t pid; int mq_id; struct mest_t msg; /* IPC_PRIVATE用於建立一個新隊列 * 設定了IPC_EXCL而且設定了IPC_CREAT。當檔案存在時返回錯誤 */ mq_id = msgget(IPC_PRIVATE, IPC_CREAT | IPC_EXCL); if (mq_id == EEXIST) return -1; /* 返回EEXIST表示IPC已存在 */ if ((pid = fork()) < 0) return -1; else if (pid == 0) { /* 子進程 */ msg.type = 123; /* 訊息類型 */ strcpy(msg.text, "Hello world!"); /* 訊息內容 */ /* 非堵塞方式將訊息放入訊息佇列 * 隊列已滿則返回EAGAIN */ while (msgsnd(mq_id, (long *)&msg, 512, IPC_NOWAIT) == EAGAIN) sleep(1); } else { /* 非堵塞方式從隊列中取訊息 * 假設沒有指定類型的訊息。函數返回-1,errno設定為ENOMSG */ while (msgrcv(mq_id, (long *)&msg, 512, 123, IPC_NOWAIT) == -1) { if (errno == ENOMSG) { printf("There is no this type message!\n"); sleep(1); } } printf("%s\n", msg.text); } return 0;}
當父進程須要取的訊息類型和子進程發送的訊息類型同樣時。執行結果例如以下:
父進程可以非常快接收到子進程發送到訊息佇列中的訊息。
可是改動msgrcv的訊息類型參數後,執行結果例如以下:
父進程得不到想要的訊息,一直列印錯誤資訊。
2、訊號量訊號量是一個計數器。用於多進程對共用資料對象的訪問。步驟例如以下:
- 測試控制該資源的訊號量。
- 若此訊號量的值為正。則進程能夠使用該資源。進程將訊號量值減1,表示它使用了一個資源單位。
- 若此訊號量的值為0。則進程進入休眠狀態,直至訊號量大於0。進程被喚醒後。它返回至第一步。
當進程不再使用由一個訊號量控制的共用資源時,該訊號量值增1。假設有進程正在休眠等待此訊號量,則喚醒它們。
3、共用儲存共用儲存同意多個進程共用一塊給定的儲存區。是最快的一種IPC。測試代碼例如以下:
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/shm.h> #define SHM_SIZE 100#define SHM_MODE (SHM_W | SHM_R | IPC_CREAT) int main(){ int shmid; char *shmptr; pid_t pid; /* 獲得共用儲存標識符 */ if ((shmid = shmget(IPC_PRIVATE, SHM_SIZE, SHM_MODE)) < 0) return -1; if ((pid = fork()) < 0) return -1; else if (pid == 0) { shmptr = shmat(shmid, 0, 0); /* 參數2為0表示由核心分配共用空間 */ printf("Child attached shared memory is : %lx\n", (unsigned long)shmptr); shmdt(shmptr); /* 使進程脫離該共用空間 */ } else { waitpid(pid, NULL, 0); shmptr = shmat(shmid, 0, 0); printf("Parent attached shared memory is : %lx\n", (unsigned long)shmptr); shmdt(shmptr); shmctl(shmid, IPC_RMID, 0); /* 刪除該共用儲存段 */ } return 0;}
執行結果:
從上面的實驗結果能夠看出,父、子進程共用了同一個儲存段。
有一點須要注意,shmdt函數僅僅是讓進程脫離該共用儲存段,但該儲存段依舊存在而且shmid依舊有效。它是與shmat相相應的。而還有一個函數shmctl使用IPC_RMID參數時才是真正刪除該共用段。
共用儲存段和儲存映射I/O中的mmap函數很相似,它們之間的差別是:mmap映射的儲存段是與檔案相關聯的,XSI共用儲存段則並無這樣的關聯。
參考:《unix編程環境》 P415-P432.
【Linux計劃】XSI IPC