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、不提供任何保护机制(同步与互斥)

相关推荐
Hacker_Nightrain35 分钟前
linux 网络安全不完全笔记
linux·笔记·web安全
一入程序无退路40 分钟前
c语言传参数路径太长,导致无法获取参数
linux·c语言·数据库
上海运维Q先生41 分钟前
面试题整理19----Metric的几种类型?分别是什么?
运维·服务器·面试
打鱼又晒网1 小时前
Linux网络 | 网络计算器客户端实现与Json的安装以及使用
linux·c++·网络协议·计算机网络
hao_wujing1 小时前
现代网络负载均衡与代理导论
运维·网络·负载均衡
朝九晚五ฺ1 小时前
【Linux探索学习】第二十三弹——理解文件系统:认识硬件、探索文件在硬件上的存储问题
linux·运维·学习
匹马夕阳1 小时前
容器化平台Docker初识
运维·docker·容器
互联网资讯1 小时前
抖音生活服务商系统源码怎么搭建?
大数据·运维·人工智能·生活
-指短琴长-2 小时前
Linux从0到1——线程同步和互斥【互斥量/条件变量/信号量/PC模型】
linux·运维·服务器
梦呓01042 小时前
platform_msi使用
linux