Linux下进程通信---共享内存之:shm

进程通信:进程与进程间的数据交换,称为进程通信。进程通讯的方式有:共享内存、信号量、管道、消息队列、socket等等。

共享内存:内核管理一片物理内存,允许不同的进程同时映射,多个进程可以映射同一块内存,被多个进程同时映射的物理内存,即共享内存。映射物理内存叫挂接,用完以后解除映射叫脱接。

优点:共享内存是进程通讯最快最有效的。

缺点:不存在同步机制,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取,需与其他机制合作来实现同步。

共享内存有两种方式:mmap、shm。

mmap:mmap方式是将文件与进程地址空间进行映射,对实际物理内存影响小。mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问,不必再调用read,write等操作。即在磁盘上建立一个文件,每个进程地址空间中开辟出一块空间进行映射。

shm:shm方式是将每个进程的共享内存与实际物理存储器进行映射,对实际物理内存影响大。即每个进程最终会映射到同一块物理内存。shm保存在物理内存,这样读写的速度要比磁盘要快,但是存储量不是特别大。

shm实现步骤:

  • fork(),获得一个key
  • shmget(),用key来创建共享内存
  • shmat(),映射共享内存,得到虚拟地址
  • 用共享内存读或者写
  • shmdt(),解除映射关系
  • shmctl(),销毁共享内存

例子如下:shm_test1.c:写入数据     shm_test2.c:读数据

//--------------------------------写入数据---------------------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include<sys/shm.h>
#include <sys/types.h>

int shm_id;
char *buff = NULL;

void fina_l(int signo)
{
	shmctl(shm_id,IPC_RMID,NULL);
	return ;
}

int main(int argc, char *argv[])
{
	int i = 0;
	int k = 0;
	key_t shm_key;

	system("> shm.txt");
	signal(SIGINT,fina_l);
	signal(SIGTERM,fina_l);

	//将指定文件,shm.txt转换成我们所需要的key,该文件必须存在且可存取,名字和数字相同就会产生相同的key,数字必须大于0
	shm_key = ftok("shm.txt",1); 
	if(shm_key == -1){
		printf("ftok is fail\n");
		return -1;
	}

	shm_id = shmget(shm_key,20,IPC_CREAT|IPC_EXCL|0777); //用key来创建共享内存
	if(shm_id == -1)
	{
		printf("shmget is fail\n");
		return -1;
	}
	for(i=0;i<3;i++)
	{
		buff = (char*)shmat(shm_id,NULL,0);  //映射共享内存,得到虚拟地址
		strcpy(buff,"hello,is me!!!");
		shmdt(buff);   //解除共享内存
	}
	
	return 0;	
}



//--------------------------------读数据---------------------------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include<sys/shm.h>
#include <sys/types.h>

int shm_id;
char *buff = NULL;

void fina_l(int signo)
{
	shmctl(shm_id,IPC_RMID,NULL);
	return ;
}

int main(int argc, char *argv[])
{
	int i = 0;
	int k = 0;
	key_t shm_key;

	system("> shm.txt");
	signal(SIGINT,fina_l);
	signal(SIGTERM,fina_l);


	sleep(2);
	//将指定文件,shm.txt转换成我们所需要的key,该文件必须存在且可存取,名字和数字相同就会产生相同的key,数字必须大于0
	shm_key = ftok("shm.txt",1); 
	if(shm_key == -1){
		printf("ftok is fail\n");
		return -1;
	}
	shm_id = shmget(shm_key,20,0);//用key来创建共享内存,0表示shm_key映射不存在,则会报错
	if(shm_id == -1)
	{
		printf("shmget is fail\n");
		return -1;
	}
	for(k=0;k<3;k++)
	{
		buff = (char *)shmat(shm_id,NULL,0);  //映射共享内存,得到虚拟地址
		printf("number: %d buff is: %s\n",k,buff);
		shmdt(buff);  //解除共享内存
		sleep(1);
	}

	shmctl(shm_id,IPC_RMID,NULL); //销毁共享内存
	return 0;	
}


结果如下:

总结:一般来说mmap方式是将文件与进程地址空间进行映射,对实际物理内存影响小,操作简单,重启会保存操作系统同步的映像和本身的文件,shm方式是将每个进程的共享内存与实际物理存储器进行映射,对实际物理内存影响大,所以一般用mmap会比较好。

猜你喜欢

转载自blog.csdn.net/weixin_42432281/article/details/87361518