栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

进程间通信-共享内存

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

进程间通信-共享内存

共享内存 共享内存的理解

共享内存是System V版本的一个进程间通信方式。共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常为同一段物理内存。进程可以将同一段物理内存连接到他们自己的地址空间中,所有的进程都可以访问共享内存中的地址。如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。

特别提醒:共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取,所以我们通常需要用其他的机制来同步对共享内存的访问,例如信号量。

共享内存通信原理

在之前学习管道时就说过多个进程之间要实现通信的话,就得让它们看到同一个资源,通过这个资源来实现通信。

在共享内存中是让他们看到同一块内存。在Linux中,每个进程都有属于自己的进程控制块(PCB)和地址空间(Addr Space),并且都有一个与之对应的页表,负责将进程的虚拟地址与物理地址进行映射,通过内存管理单元(MMU)进行管理。两个不同的虚拟地址通过页表映射到物理空间的同一区域,它们所指向的这块区域即共享内存

 

当两个进程通过页表将虚拟地址映射到物理地址时,在物理地址中有一块共同的内存区,即共享内存,这块内存可以被两个进程同时看到。这样当一个进程进行写操作,另一个进程读操作就可以实现进程间通信。但是,我们要确保一个进程在写的时候不能被读,因此我们使用信号量来实现同步与互斥 。

但是我们要怎么判断两个进程是挂载到了同一块内存空间,因为内存空间中可能不止一个共享内存,这里我们了解一个创建key值的函数ftok()函数,这里的key值就是这块共享内存空间的唯一标识符。两个进程通过同一个key值挂载到同一块共享内存。

key_t ftok(const char* pathname,int proj_id);

参数解释:

​ *pathname就是你指定的文档名

​ proj_id是子序号

返回值:成功返回一个key值,失败返回-1。

nattch是共享内存的挂载计数器,对于一个共享内存,实现采用的是引用计数的原理,当进程脱离共享存储区后,计数器减一,挂载成功时,计数器加一,只有当计数器变为零时,才能被删除。当进程终止时,它所附加的共享存储区都会自动脱离。

共享内存的接口函数以及指令 指令

1查看系统中的共享储存

ipcs -m

2手动删除系统中的共享内存

ipcrm -m [shmid]

接口函数

1、创建共享内存

int shmget(key_t key,size_t size, int shmflg)

参数解释:

​ key: ftok()函数生成的key值,标识系统中唯一的IPC资源。

​ size:我们要申请的共享内存大小,最好是页的整数倍,一页是4k字节。

​ shmflg:如果要创建新的共享内存,需要使用IPC_CREAT,IPC_EXCL,如果是已经存在的,可以使用IPC_CREAT或者直接传0。

返回值:

​ 成功时返回一个新建或已经存在的的共享内存标识符,取决于shmflg的参数。失败返回-1并设置错误码。

2、挂载共享内存

void* shmat(int shmid,const void *shmaddr,int shmflg);

参数解释:

​ shmid:共享内存的标识符。

​ shmaddy:shmaddr=0,则存储段连接到由内核选择的第一个可用地址上(推荐使用)。

​ shmflg:若指定了SHM_RDONLY位,则以只读方式链接共享内存,否则以读写方式链接。

返回值:

​ 成功返回共享存储段的指针(虚拟地址),并且内核将使其与该共享存储段相关的shmid_ds结构中的shm_nattch计数器加1(类似于引用计数);出错返回-1 。

3、去关联共享内存

当进程之间完成通信时,就需要去关联,需要将该进程从之前连接的共享内存上脱离下来。

int shmdt(const void* shmaddr);

参数解释:

​ shmaddr:shmat()函数成功的返回值。

返回值

​ 成功返回0,并将shmid_ds结构体中的 shm_nattch计数器减1;出错返回-1

4、释放共享内存

当shm_nattch为0时就需要释放这块共享内存,否则就会一直占用下去,因为共享内存的生命周期是跟随内核的。

int shmctl(int shmid,int cmd,struct shmid_ds* buf);

参数解释:

​ shmid:共享内存标识符。

​ cmd:指定执行的操作,设置为IPC_RMID时表示释放共享内存。

​ buf:暂时不需要了解,设置为NULL就行。

返回值:

​ 成功返回0,失败返回-1.

模拟共享内存
//server.c
#include    
#include    
#include"comm.h"    
#include    
#include    
#include    
int main()    
{    
  //ftok创建key值    
  key_t k=ftok(PATHNAME,PROJ_ID);    
    
  //根据key值创建共享内存    
  int shmid=shmget(k,SIZE,IPC_CREAT|IPC_EXCL|0666);    
  //判断是否创建成功    
  if(shmid<0)    
  {    
    perror("shmget");    
    return 1;    
  }    
  //挂载共享内存    
  char* str=(char*)shmat(shmid,NULL,0);    
  //int i=0;    
  while(1)    
  {    
    //i++;                                                                                                                                                   
    sleep(1);    
    printf("%sn",str);    
  }    
  //去关联    
  shmdt(str);    
  //释放共享内存    
  shmctl(shmid,IPC_RMID,NULL);    
  return 0;    
}   
//client.c
#include 
#include    
#include"comm.h"     
#include                                                                          
#include                                                                            
#include                                                                             
int main()                                                                                   
{                                                                                   
  //ftok创建key值                                                                                   
  key_t k=ftok(PATHNAME,PROJ_ID);                                                                                   
                                                                                   
  //根据key值找到共享内存                                                                                   
  int shmid=shmget(k,SIZE,0);                                                                                                         
  //判断是否创建成功                                                                                   
  if(shmid<0)                                                                                   
  {                                                                                   
    perror("shmget");                                                                                   
    return 1;                                                                                   
  }                                                                                   
  //挂载共享内存                                                                                   
  char* str=(char*)shmat(shmid,NULL,0);                                                                                   
  char c='a';                                                                                  
  for(;c<='z';c++)                                                                           
  {                                                                                   
    str[c-'a']=c;                                                             
    sleep(2);
  }
  //去关联
  shmdt(str);
  //这里不用释放共享内存,只需要释放一次就可以,server.c已经释放了。
  //shmctl(shmid,IPC_RMID,NULL);
  return 0;
}   

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/829881.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号