進程間通信-共享內存

共享內存:使得多個進程可以訪問同一塊內存空間,是最快的可用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;
}


效果如下:








發佈了85 篇原創文章 · 獲贊 56 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章