共享內存:使得多個進程可以訪問同一塊內存空間,是最快的可用IPC通信形式。是針對其他通信機制運行效率較低而設計的,往往與其它通信機制,如信號量結合使用,來達到進程間的同步及互斥。
機制如下:
特點:
1.內存共享是進程間通信速度最快的:
由上圖可知,內存共享是進程1從其地址空間直接寫到物理內存中,進程2則直接通過地址空間虛擬地址從內存中取,不需要通過進入內核來傳遞消息,而消息隊列,信號量則都要在內核開闢一塊空間,進程通信傳遞需從用戶區拷貝到內核區,再從內核區拷貝到用戶區,所以其不涉及內核的拷貝,所以其效率較高。
2.共享內存不帶任何同步、互斥機制,所以其一般都與信號量匹配使用;
3.共享內存開闢在物理內存上,所以其生命週期爲隨內核。
Linux下共享內存的兩條命令:
ipcs -m ; //查看共享內存
ipcrm -m <shmid>; //刪除共享內存
1.創建共享內存:
函數:
int shmget(key_t key,size_t size,int shmflag);
參數:
key:共享內存唯一的鍵值,用ftok()函數獲取;
size:申請的內存大小,一般爲頁的整數倍,因爲系統分配的大小始終爲頁的整數倍,1頁=4k;
shmflag:IPC_CREAT(單獨使用沒有創建共享內存,創建新的共享內存,若有,則返回存在的共享內存),IPC_EXCL(與IPC_CREAT合用,不存在,創建新的,存在返回錯誤碼);
返回值:
成功返回共享內存id,失敗返回錯誤碼。
2.刪除共享內存:
函數:
int shmctl(int shmid,int cmd,struct shmid_ds* buf);
參數:
shmid:共享內存id;
cmd:刪除時設爲IPC_IMID;
buf:對共享內存的修改或對其查看,若cmd設爲IPC_IMID,則設爲NULL;
3.共享內存的掛接:
函數:(此函數用法與malloc()相同)
void* shmat(int shmid,const void* shmaddr,int shmflg);
參數:
shmid:共享內存id;
shmaddr:共享內存與指定虛擬地址建立映射關係,一般設爲NULL,即由操作系統安排;
shmflg:一般設爲缺省0;
返回值:
建立映射關係後返回的虛擬地址。
4.與共享內存斷開聯繫:
函數:
int shmdt(const void* shmaddr);
參數:
shmaddr:shmat()函數的返回值虛擬地址;
代碼實現:
comm.h
#ifndef _COMM_H__
#define _COMM_H__
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#define PATH "."
#define PROJ_ID 0x6666
int creatShm(int size); //創建
int getShm(int size); //獲取
int destroyShm(int shmid); //刪除
#endif //_COMM_H__
server.c(讀打印)
#include "comm.h"
int main()
{
int shmid=creatShm(4096); //創建共享內存
//printf("create success!!! shmid:%d\n",shmid);
sleep(3);
char* addr=shmat(shmid,NULL,0); //使當前進程與共享內存掛接 ,此函數返回進程虛擬地址
int i=0; //第二個參數爲指定的虛擬地址,一般由操作系統指定,所以設爲null
while(i<26)
{
printf("%s\n",addr); //打印地址(讀共享內存處內容)處內容
sleep(1);
++i;
}
shmdt(addr); //使當前進程與共享內存斷開關聯
int ret=destroyShm(shmid);
//printf("destroy success. ret:%d\n",ret);
return 0;
}
client.c(寫)
#include "comm.h"
int main()
{
int shmid=getShm(4096); //獲取已創建好的共享內存
printf("getShm success!! shmid:%d\n",shmid);
char* addr=shmat(shmid,NULL,0); //使當前進程與共享內存掛接 ,此函數返回進程虛擬地址
int i=0;
while(i<26)
{
addr[i]='A'+i; //向共性內存處寫內容
sleep(1);
++i;
addr[i]=0;
}
shmdt(addr); //使當前進程與共享內存斷開關聯
return 0;
}
comm.c
#include "comm.h"
static int commShm(int size,int flags)
{
key_t _key=ftok(PATH,PROJ_ID);
if(_key<0)
{
perror("ftok");
return -1;
}
int shmid=shmget(_key,size,flags); //創建或獲取共享內存 參數size爲頁的整數倍(會自動調整) 1頁=4k
if(shmid<0)
{
perror("shmget");
return -2;
}
return shmid;
}
int creatShm(int size)
{
return commShm(size,IPC_CREAT|IPC_EXCL|0666);
}
int getShm(int size)
{
return commShm(size,IPC_CREAT);
}
int destroyShm(int shmid)
{
if(shmctl(shmid,IPC_RMID,NULL)<0) //立即刪除shmid標識的共享內存
{
perror("destroy:shmctl");
return -1;
}
return 0;
}