进程间通信------共享内存

共享内存

  • 共享内存区是最快的IPC形式。⼀旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执⾏进入内核的系统调⽤来传递彼此的数据。
  • 先简单介绍一下,也有把共享内存叫做共享存储,共享存储允许两个或者多个进程共享一个给定的存储区。因为数据不需要在客户进程和服务器进程之间复制,所以这是最快的一种 IPC。使用共享存储时要掌握的诀窍就是,在多个进程之间同步访问一个给定的存储区。若服务器进程正在将数据放入共享存储区,则在他做完这一操作之前,客户进程不应该去取这些数据。
  • 共享存储就是在多个进程将同一个文件映射到它们的地址空间。共享存储和内存映射的文件的不同之处在于,共享存储没有相关的文件。共享存储段是内存的匿名段。

共享内存函数

- shmget 函数
  • 功能:用来创建共享内存
  • 原型 int shmget(key_t key, size_t size, int shmflg);
  • 参数
    • key:这个共享内存段名字
    • size:共享内存⼤小
      • 这个大小以字节为单位。实现通常将其向上取为系统页长的整数倍,如果应用指定的size值并非系统页长的整数倍,那么最后一页的余下部分是不可使用的。
      • 如果创建一个新段(通常在服务器进程中),则必须指定其size。如果正在引用一个现存的段(一个客户进程),则将size指定为0,。当创建一个新段是,段内的内容初始化为0。
    • shmflg:由九个权限标志构成,它们的⽤用法和创建⽂文件时使⽤用mode模式标志是⼀样的
  • 返回值:成功返回⼀个非负整数,即该共享内存段的标识码;失败返回 -1
shmat 函数
  • 功能:将共享内存段连接到进程地址空间
  • 原型 void *shmat(int shmid, const void *shmaddr, int shmflg);
  • 参数
    • shmid : 共享内存标识
    • shmaddr : 指定连接的地址
    • shmflg : 它的两个可能取值是 SHM_RND和SHM_RDONLY
  • 返回值:成功返回⼀个指针,指向共享内存第⼀个字节;失败返回 -1。如果shmat成功执行,那么内核将使与该共享存储段相关的shmid_ds结构中的shm_nattch计数器值加1。
  • 注意:
    • shmaddr 为NULL,则此段连接到由内核选择的一个可用地址上,则是推荐的使用方式。
    • shmaddr不为 NULL 且 shmflg ⽆ SHM_RND 标记,则以shmaddr为连接地址。
    • shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会⾃动向下调整为SHMLBA的整数倍。
      • 公式:shmaddr - (shmaddr % SHMLBA)
    • 除非只计划在一种硬件上运行应用程序(这在当今是不大可能的),否则不应指定共享内存段所连接到地址。而是应当指定shmaddr为NULL,以便由系统来选择地址。
  • shmflg=SHM_RDONLY,表示连接操作用来只读共享内存,否则以读写方式连接此段。
  • 当对共享内存的操作结束时,则调用shmdt 与该段分离。注意:这不从系统中删除其标识符以及相关的数据结构。该标识符依然存在,直至某个进程(一般是服务器进程)带IPC_RMID命令的调用shmctl 特地删除它为止。
shmdt 函数
  • 功能:将共享内存段与当前进程脱离
  • 原型 int shmdt(const void *shmaddr);
  • 参数
    • shmaddr: 由shmat所返回的指针
  • 返回值:成功返回0;失败返回-1
  • 注意:将共享内存段与当前进程脱离不等于删除共享内存段
shmctl 函数
  • 功能:⽤用于控制共享内存
  • 原型 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
  • 参数
    • shmid:由shmget返回的共享内存标识码
    • cmd:将要采取的动作(有三个可取值)
      • IPC_STAT:取此段的shmid_ds结构,并将它存储在由buf指向的结构中。
      • IPC_SET:按buf指向的结构体中的值设置与此共享存储段相关的shmid_ds结构中的字段。
      • IPC_RMID:从系统中删除该共享内存
命令 说明
IPC_STAT 把shmid_ds结构中的数据设置为共享内存的当前关联值
IPC_SET 在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds数据结构中给出的值
IPC_RMID 删除共享内存段
  • buf:指向⼀个保存着共享内存的模式状态和访问权限的数据结构
  • 返回值:成功返回0;失败返回-1

来看一个共享内存的代码

  1 #include<unistd.h>
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<sys/shm.h>
  5 
  6 #define IPC_KEY  0x1234567
  7 
  8 int main()
  9 {
 10     int shmid1 = 0;
 11     shmid1 = shmget(IPC_KEY,32, IPC_CREAT | 0664);
 12     if(shmid1 < 0)
 13     {
 14         perror("shmget error\n");
 15         return -1;
 16     }
 17     void *shm_start = shmat(shmid1,NULL,0);
 18     if(shm_start == (void*)-1)
 19     {
 20         perror("shmat error");
 21         return -1;
 22     }
 23 
 24     int i = 1;
 25     while(1)
 26     {
 27         sprintf(shm_start,"%s-----%d\n","hello",i++);
 28         sleep(1);
 29     }
 30 
 31 
 32     return -1;
 33 }

  1 #include<unistd.h>
  2 #include<stdio.h>
  3 #include<stdlib.h>
  4 #include<sys/shm.h>
  5 
  6 #define IPC_KEY  0x1234567
  7 
  8 int main()
  9 {
 10     int shmid = -1;
 11     shmid = shmget(IPC_KEY,32, IPC_CREAT|0664);
 12     if(shmid < 0)
 13     {
 14         perror("shmget error\n");
 15         return -1;
 16     }
 17     void *shm_start = shmat(shmid,NULL,0);
 18     if(shm_start == (void*)-1)
 19     {
 20         perror("shmat error");
 21         return -1;
 22     }
 23     while(1)
 24     {
 25         printf("不断的问自己:%s",shm_start);
 26         sleep(1);
 27     }
 28 }

进程间通信------共享内存