Linux共享存儲通信
內容
- 創建共享存儲區實現進程通信
機理說明
共享存儲區(Share Memory)是Linux系統中通信速度最高的通信機制。該機制中共享內存空間和進程的虛地址空間滿足多對多的關系。即一個共享內存空間可以映射多個進程的虛地址空間,一個進程的虛地址空間又可以連接多個共享存儲區。當進程間預利用共享存儲區通信時,先要在主存中建立一個共享存儲區,然后將它附接到自己的虛地址空間。該機制只為進程提供了用於實現通信的共享存儲區和對共享存儲區進行操作的手段,然而並未提供對該區進行互斥訪問及進程同步的措施。
調用函數說明
創建共享內存
shmget(key ,size ,flag)
功能:獲得一個內部標識為shmid的共享存儲區。
語法:int shmget = int shmget(key_t key ,int size ,int flag);
參數說明:
key 共享存儲區關鍵字,可由用戶指定。若使用IPC_PRIVATE則其值由系統產生。
size 存儲區大小(字節數)。若存儲區定義為字符型,則大小為定義的字符個數;若定義為整型,大小可以用sizeof(int)加以定義
flag 用戶設置的標志或訪問方式,如0666|IPC_CREAT,表示任意進程皆可讀可寫
操作允許權 | 八進制數 | 操作允許權 | 八進制數 |
---|---|---|---|
用戶可讀 | 0400 | 小組可寫 | 0020 |
用戶可寫 | 0200 | 其它可讀 | 0004 |
小組可讀 | 0040 | 其它可寫 | 0002 |
附接共享內存
字符型共享內存:
shmat(int shmid ,char *shmadddr ,int msgflg ,ulong * raddr);
數值型共享內存:
shmat(int shmid ,int *shmadddr ,int msgflg ,ulong * raddr);
語法格式:
字符型共享內存:
viraddr = (char *) shmat (shmid ,shmaddr ,shmflag);
viraddr = (int *) shmat (shmid ,shmaddr ,shmflag);
參數說明:
shmid共享存儲區的描述符,可由shmget()的返回值得到。
shmaddr用戶提供的共享存儲區附接的虛地址。
shmflag規定存儲區的操作權限。如,SHM_RND則表示操作系統在必要時舍去地址;SHM_RDONLY則表示只允許讀,shmflag為0表示可讀可寫。
斷開共享內存
shmdt(viraddr)
參數說明:
viraddr系統調用shmat()所返回的虛地址。
返回值:
函數被正確調用則返回0,錯誤返回-1
shmctl(int shmid ,int cmd ,struct shmid_ds * buf);
功能:對共享內存進行操作控制
參數說明:
shmid共享存儲區的描述符,可由shmget()的返回值得到。
buf用戶級數據結構地址,可為0。
cmd規定的操作類型
操作代碼 | 含義 |
---|---|
IPC_STAT | 返回指定shmid數據結構的狀態信息,放置於*buf中,必須有讀取允許權 |
IPC_SET | 設置指定shmid的有效用戶和操作存取權 |
IPC_RMID | 刪除指定shmid以及與它相關的共享存儲區的數據結構 |
SHM_LOCK | 在內存中鎖定指定的共享存儲區,必須是root才能執行 |
shmctl(shmid ,IPC_RMID ,0); //撤銷共享內存區
實現思路
send:
- shmget()創建或者獲取指定key值的共享內存
- shmat()將該內存附接到自己的虛擬地址空間
- 將消息寫入共享內存
- 字符:
- 以追加方式寫入,strcat(viraddr ,buffer)
- 以覆蓋方式寫入,strcpy(viraddr ,buffer)
- 數字:
- 直接賦值
- 操作數組\
- 字符:
- shmdt()斷開共享內存
receive:
- shmget()創建或者獲取指定key值的共享內存
- shmat()將該內存附接到自己的虛擬地址空間
- 輸出信息
- shmdt()斷開共享內存
- shmctl()撤銷內存
實例
send
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/shm.h>
/*共享內存 share memory 實現的進程通信*/
main()
{
int shmid;
char *viraddr;
char buffer[BUFSIZ];
shmid=shmget(1234,BUFSIZ,0666|IPC_CREAT);
viraddr=(char*)shmat(shmid,0,0);
while(1)
{
puts("Enter some text:");
fgets(buffer,BUFSIZ,stdin);/*從標准輸入設備讀入一行字符串,stdin是標准輸入,C標准庫里面的一 個全局變量*/
strcat(viraddr,buffer); /*字符串追加函數*/
if(strncmp(buffer,"end",3)==0)/*比較兩個字符串數組*/
break;
}
shmdt(viraddr);
exit(0);
}
receive
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/shm.h>
main()
{
int shmid;
char *viraddr;
shmid=shmget(1234,BUFSIZ,0666|IPC_CREAT);
viraddr=(char*)shmat(shmid,0,0);
printf("Your message is :\n%s",viraddr);
shmdt(viraddr); /*斷開連接*/
shmctl(shmid,IPC_RMID,0); /*撤銷共享內存*/
exit(0);
}
運行結果
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/shm.h>
/* 父進程與子進程間的通信,子進程寫信息到共享內存中,父進程讀取該信息
BUFSIZ為全局量定義在<stdlib.h>,8192
使用exit(0)和wait(0)進行同步*/
main()
{
int chld,shmid;
char *viraddr;
char buffer[BUFSIZ];
shmid=shmget(IPC_PRIVATE,BUFSIZ,0666|IPC_CREAT);
viraddr=(char*)shmat(shmid,0,0);
while((chld=fork())==-1);
if(chld==0)
{ /*子進程塊*/
while(1)
{
puts("Enter some text:"); /*寫信息到共享內存*/
fgets(buffer,BUFSIZ,stdin); /*用戶輸入信息*/
strcat(viraddr,buffer); /*附接到進程的虛擬空間*/
if(strncmp(buffer,"end",3)==0)
break; /*輸入end結束*/
}
exit(0);
}
else
{ /*父進程塊*/
wait(0);
printf("Your message is:\n%s",viraddr);
shmdt(viraddr); /*斷開共享內存*/
shmctl(shmid,IPC_RMID,0); /*釋放共享內存*/
exit(0);
}
}
運行結果