Linux關於程序間通訊共享記憶體
共享記憶體概念
共享記憶體允許兩個不相關的程序去訪問同一部分邏輯記憶體 如果需要在兩個執行中的程序之間傳輸資料,共享記憶體將是一種效率極高的解決方案
共享記憶體是由IPC為一個程序建立的一個特殊的地址範圍,它將出現在程序的地址空間中。 其他程序可以把同一段共享記憶體段“連線到”它們自己的地址空間裡去。 所有程序都可以訪問共享記憶體地址,就好像它們是有malloc分配的一樣 如果一個程序向這段共享記憶體寫了資料,所做的改動會立刻被有權訪問同一段共享記憶體的其他程序看到
關於共享記憶體的操作
以下程式碼建立一塊共享記憶體
#include<stdio.h> #include<sys/types.h> #include<sys/shm.h> #include<sys/ipc.h> #include<string.h>
int main() { int shmid = shmid = shmget((key_t)1234,2048,IPC_CREAT|0766); printf("shmid = %d\n",shmid); return 0; }
但實際我們要這樣建立,先刪除之前可能存在的記憶體,在建立一塊自己的記憶體
#include<stdio.h> #include<sys/types.h> #include<sys/shm.h> #include<sys/ipc.h> #include<string.h>
int main() { int shmid = shmget((key_t)1234,0,0); if(shmid > 0) { shmctl(shmid,IPC_RMID,0); shmid = shmget((key_t)1234,2048,IPC_CREAT|0766); printf("shmid = %d\n",shmid); } return 0; }
下面演示為什麼要這樣做
#include<stdio.h> #include<sys/types.h> #include<sys/shm.h> #include<sys/ipc.h> #include<string.h>
int main() { // int shmid = shmget((key_t)1234,2048,IPC_CREAT|0766); int shmid = shmget((key_t)1234,0,0); if(shmid > 0) { shmctl(shmid,IPC_RMID,0); shmid = shmget((key_t)1234,2048,IPC_CREAT|0766); } void *ptr = shmat(shmid,NULL,0); memcpy(ptr,"helloworld",strlen("helloworld")); printf("shmid = %d\n",shmid); return 0; }
先註釋掉第一段程式碼是最開始實現的開闢共享記憶體,剩下的是第二種方法實現開闢共享記憶體,我們執行程式,不會出錯
當我們把第一段程式碼釋放掉,下面實現的第二種方法註釋起來
#include<stdio.h> #include<sys/types.h> #include<sys/shm.h> #include<sys/ipc.h> #include<string.h>
int main() { int shmid = shmget((key_t)1234,4096,IPC_CREAT|0766); //int shmid = shmget((key_t)1234,0,0); //if(shmid > 0) //{ // shmctl(shmid,IPC_RMID,0); // shmid = shmget((key_t)1234,2048,IPC_CREAT|0766); //} void *ptr = shmat(shmid,NULL,0); memcpy(ptr,"helloworld",strlen("helloworld")); printf("shmid = %d\n",shmid); return 0; }
出現以下結果:
我們來分析一下,仔細看紅色的那一段程式碼,我們把開闢的記憶體開闢成4096,當我們之前的記憶體沒有清掉,此時我們使用共享記憶體是一樣的,但是開闢出來更大的空間,此時使用shmat對映邏輯地址就會出現段錯誤。
所以當我們進行伺服器開發的時候,如果同組成員之前開闢了共享記憶體ID為1234,而我們後面也開闢了ID為1234的共享記憶體,但是我們不知道他開闢了多大,如果一旦開闢不一樣大,進行對映邏輯地址的時候就會出錯。避免這樣的事情發生,我們在開闢共享記憶體之前,對共享記憶體進行刪除,再進行建立,就會避免這樣的事情發生。