Linux——进程间通信(共享内存)

目录

[system V共享内存](#system V共享内存)

​编辑

共享内存函数

共享内存的建立过程

shmget函数

shmctl函数

shmat函数

shmdt函数

实例代码

共享内存的特点


system V共享内存

共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间(即内存通过某种映射关系连接到了进程使得进程能够访问这段内存),这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。

共享内存函数

我们之前的文章介绍的管道通信本质是基于文件的,OS没有做过多的设计工作。

而system V进程间通信是OS特地设计的通信方式,是为了想尽一切办法让不同的进程看到同一份资源。(具体的方法就是将物理内存映射到进程的地址空间中,本质就是修改页表,在虚拟地址空间中开辟空间,用的是系统调用接口)

共享内存的建立过程

1、申请共享内存

2、共享内存挂接到地址空间

3、去关联共享内存

4、释放共享内存

前两点式通信过程,后两点是释放资源的过程

shmget函数

功能:用来创建共享内存

原型

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

参数

key:这个共享内存段名字

size:共享内存大小

shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样 的

返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1

cpp 复制代码
 //comm.h                                                                                                                                                                                     
  1 #ifndef _COMM_H_ 
  2 #define _ COMM_H_
  3 #include <stdio.h>
  4 #include <sys/types.h>
  5 #include <sys/ipc.h>
  6 #include <sys/shm.h>
  7 
  8 #define PATHNAME "."
  9 #define PROJ_ID 0x6666
 10 #define SIZE 4096
 11 
 12 #endif                                                                                                                                                                                                       
cpp 复制代码
    //sever.c
    1 #include "comm.h"
    2 #include <unistd.h>
    3 int main()
    4 {
    5   key_t k = ftok(PATHNAME, PROJ_ID);
    6   if(k < 0)
    7   {
    8     perror("ftok");
    9     return 1;
   10   }
   11   printf("%x\n", k);
   12   int shmid = shmget(k, SIZE, IPC_CREAT|IPC_EXCL|0644);
   13   if(shmid < 0)
   14   {
   15     perror("shmget");
   16     return 2;
   17   }
   18  
   19   return 0;
   20 }

运行这一段代码,便能成功创建一块共享内存,可以使用ipcs -m命令查看

shm的生命周期是随内核的,进程不主动删除或者用命令删除,共享内存就一直存在,直到关机重启。

释放这一块空间则是用命名ipcrm -m [shmid]

当然这块内存的释放也有函数可以使用,没必要在命令行进行这么麻烦的操作

shmctl函数

功能:用于控制共享内存

原型

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

参数

shmid:由shmget返回的共享内存标识码

cmd:将要采取的动作(有三个可取值)

buf:指向一个保存着共享内存的模式状态和访问权限的数据结构

返回值:成功返回0;失败返回-1

在上面创建的server.c中结尾加上这一段

cpp 复制代码
   sleep(10);
   shmctl(shm, IPC_RMID, NULL);
   sleep(10);    

运行这一段代码,可以看到共享内存一开始被创建,然后过了一会就被删除了

至此我们就完成了共享内存的创建与释放,那么接下来要解决的问题就是如何进行映射了

shmat函数

功能:将共享内存段连接到进程地址空间

原型

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

参数

shmid:共享内存标识

shmaddr:指定连接的地址

shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY

返回值:成功返回一个指针,指向共享内存的第一个节;失败返回-1

cpp 复制代码
    1 #include "comm.h"
    2 #include <unistd.h>
    3 #include <string.h>
    4 #include <sys/types.h>
    5 #include <sys/ipc.h>
    6 #include <sys/shm.h>
    7 int main()
    8 {
    9   key_t _key = ftok(PATHNAME, PROJ_ID);
   10   if(_key < 0)
   11   {
   12     perror("ftok");
   13     return -1;
   14   }
   15   printf("%x\n",_key);
   16   int shmid = 0;
   17   if((shmid = shmget(_key, SIZE, IPC_CREAT|IPC_EXCL|0644)) < 0)
   18   {
   19     perror("shmget");
   20     return -2;
   21   }
   22 
   23   printf("shmid: %d\n", shmid);
   24 
   25   printf("attach begin!\n");
   26   sleep(3);
   27   char* mem = shmat(shmid, NULL, 0);
   28   if(mem == (void*)-1)
   29   {
   30     perror("shmat");
   31     return 3;
   32   }                                                                                             
   33   printf("attach end!\n");
   34   sleep(3);
   35 
   36   shmctl(shmid, IPC_RMID, NULL);
   37 
   38   return 0;
   39 }

说明:

shmaddr为NULL,核心自动选择一个地址

shmaddr不为NULL且shmflg无SHM_RND标识,则以shmaddr为连接地址

shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHML BA的整数倍。公式:shmaddr - (shmaddr % SHML BA)

shmflg=SHM_RDONLY,表示连接操作用来只读共享内存

shmdt函数

功能:将共享内存段与当前进程脱离

原型

int shmdt(const void *shmaddr);

参数

shmaddr:由shmat所返回的指针

返回值:成功返回0;失败返回-1

注意:将共享内存段与当前进程脱离不等于删除共享内存段

取消关联即在上面那段代码中的释放共享内存前加入

cpp 复制代码
shmdt(mem);

即可取消进程与共享内存间的关联

实例代码
cpp 复制代码
//comm.h
  1 #ifndef _COMM_H_ 
  2 #define _ COMM_H_
  3 #include <stdio.h>
  4 #include <sys/types.h>
  5 #include <sys/ipc.h>
  6 #include <sys/shm.h>
  7 
  8 #define PATHNAME "."
  9 #define PROJ_ID 0x6666
 10 #define SIZE 4096
 11 
 12 #endif        
cpp 复制代码
//server.c
    1 #include "comm.h"
    2 #include <unistd.h>
    3 int main()
    4 {
    5   key_t k = ftok(PATHNAME, PROJ_ID);
    6   if(k < 0)
    7   {
    8     perror("ftok");
    9     return 1;
   10   }
   11   printf("%x\n", k);
   12   int shmid = shmget(k, SIZE, IPC_CREAT|IPC_EXCL|0644);
   13   if(shmid < 0)
   14   {
   15     perror("shmget");
   16     return 2;
   17   }
   18 
   19   printf("shmid: %d\n", shmid);
   20 
   21   sleep(5);
   22   char* mem = shmat(shmid, NULL, 0);
   23   while(1)
   24   {
   25   printf("client msg# %s\n", mem);
   26   sleep(1);                                                                                     
   27   }
   28   shmdt(mem);
   29 
   30   shmctl(shmid, IPC_RMID, NULL);
   31 
   32   return 0;
   33 }
   34 
cpp 复制代码
//client.c
    1 #include "comm.h"
    2 #include <unistd.h>
    3 #include <string.h>
    4 int main()
    5 {
    6   key_t k = ftok(PATHNAME, PROJ_ID);
    7   if(k < 0)
    8   {
    9     perror("ftor");
   10     return 1;
   11   }
   12   int shmid = shmget(k, SIZE,0644);
   13   if(shmid < 0)
   14   {
   15     perror("shmget");
   16     return 2;
   17   }
   18 
   19   char* mem = shmat(shmid, NULL, 0);
   20 
   21   int i = 0;                                                                                    
   22   while(1)
   23   {
   24     mem[i] = 'A' + i;
   25     sleep(1);
   26     i++;
   27     mem[i] = 0;
   28   }
   29 
   30   shmdt(mem);
   31 
   32   return 0;
   33 }

可以看到我们实现了client端向server端通过共享内存进行信息的传输

共享内存的特点

1、共享内存是所有进程通信中速度最快的,因为它没有使用OS接口,拷贝次数减少

2、不提供任何保护机制(同步与互斥)

相关推荐
爱吃龙利鱼2 小时前
网络基础知识笔记(五)接口管理
运维·网络·笔记·云原生·智能路由器
陈小肚2 小时前
DNS 反向解析导致 ssh 连接缓慢
运维·ssh
zbdx不知名菜鸡2 小时前
linux基础 超级笔记
linux·运维·服务器
wellnw2 小时前
【IPv6】IPv6地址格式及地址分类(组播、单播、任播)整理
运维·服务器·网络
wanhengwangluo3 小时前
高防服务器的优劣势有哪些?
运维·服务器
总是学不会.3 小时前
SpringBoot项目:前后端打包与部署(使用 Maven)
java·服务器·前端·后端·maven
shelby_loo4 小时前
在Ubuntu下通过Docker部署NAS服务器
服务器·ubuntu·docker
李的阿洁5 小时前
OSPF的不规则区域
运维·服务器·网络
网安老伯5 小时前
【2024版】最新kali linux入门及常用简单工具介绍(非常详细)零基础入门到精通,收藏这一篇就够了_kalilinux
linux·运维·服务器·开发语言·web安全·网络安全·xss
逸狼5 小时前
【JavaEE初阶】网络原理
服务器·网络·智能路由器