【Linux】system V 共享内存(下)

简介: 【Linux】system V 共享内存

1. 创建key值


e77425d60f69484387fc398f47c938a2.png

comm.hpp 公共路径中构建一个函数 Getkey 用于返回key值


5425314557c94fe6a7b74611d186f7f1.png


构建一个函数 tohex,用于将数转换为十六进制


5537743d21a0448487e8e4f3afe305ef.png


通过server.cc与client.cc中分别调用Getkey 与tohex函数


a58a1a217d7b47999e545a5bc18e2681.png


两者的返回值key 是相同的,并且返回的都是十六进制数


2. 创建共享内存 获取共享内存


6775b00a931a44d2bf7c417a79a675a0.png


创建共享内存,调用shmget函数,通过两个选项 若共享内存不存在则创建,若存在则报错

而获取共享内存,调用shmget函数,则返回已有的共享内存


c5bfcb71c23d4823b038b5ec4902bc9e.png

此时运行可执行程序,发现server与client的shmid(共享内存标识符)相同

3. 将自己和共享内存关联起来

输入 man shmat 指令

4b23b2dcffdb4db18394ce6d922f0288.png

at代表 关联

将共享内存和目标值关联起来

返回值为 共享内存的虚拟地址的起始地址

我们不知道应该把共享内存放在虚拟空间的什么地址处,所以shmaddr设为NULL让系统自主去选择

shmflg 可以设置为 SHM_RDONLY 表示当前共享内存是只读的 一般设为0,默认为读写的

4e5997f75fe34fa08b4091f079dd2a8f.png

4. 将自己和共享内存取消关联

输入 man shmdt 指令


c9185451f828442ea0318be447722882.png

shmdt代表 虚拟地址

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

813d452a405743f69e618dad1bd0159a.png

5. 删除共享内存

创建共享内存的进程已经早就退出了,但是共享内存还存在

确认共享内存存在: ipcs

ipc作为进程间通信的简写

ipc表示资源 s表示有多个资源

e9d629efc4b749639e6fd7a241092a06.png

显出来的为ipc通信系统所支持的三种ipc通信策略

Message Queues 消息队列

Shared Memory Segments 共享内存段

Semaphore Arrays 信号量

ipcs - m 查看共享内存段

020dad6ef00d499f84769b3c6d273a55.png

perms 代表权限

bytes 代表字节数

nattch 代表 有几个进程和当前进程是关联的

用指令删除

key是在操作系统中使用的,类似于文件的inode编号

shmid 类似于文件的fd

所以删除操作,是在用户层,应该用shmid

6c8cf20f0687429d9c789b5c3db32a09.png


ipcrm -m shmid值 就可以删除共享内存

此时就没有 shmid为0的共享内存 存在了

调用系统调用

输入 man shmctl 指令


1b95bdbfbbc8482abc3a43bae6f747cd.png

shmid 代表 共享内存描述符 即想对那个共享内存操作

cmd 代表 选项 即想做什么操作

IPC_STAT 获取当前共享内存的属性

IPC_SET 设置共享内存属性

IPC_RMID 标记这个段被释放

buf 代表 共享内存的属性

87f570f004ba4c0da49499faf81c2b8e.png


在comm.hpp下 设置删除共享内存的函数,在server.cc中调用函数 即可删除共享内存

完整代码

makefile

.PHONY:all
all:server client
server:server.cc
  g++ -o $@ $^
client:client.cc
  g++ -o $@ $^
.PHONY:clean
clean:
  rm -f server client 

如何使两个可执行程序运行,在上一篇文章提到过,点击查看:命名管道


comm.hpp

#ifndef _COMM_HPP_
#define _COMM_HPP_
#include<iostream>
#include<cerrno>
#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<assert.h>
using namespace std;
#define PATHNAME "."//.表示当前路径  路径字符串
#define PROJID 0x6666 //项目id
const int gsize=4096;
key_t getkey()//用于返回key值
{
    key_t k=ftok(PATHNAME,PROJID);
    if(k==-1)//失败
    {
       cout<<errno<< " :" <<strerror(errno)<<endl;
       exit(1);
    }
    return k;//返回key值
}
string tohex(int x)//转换为十六进制
{
   char buffer[64];
   //将x以十六进制的形式传给buffer
   snprintf(buffer,sizeof(buffer),"0x%x",x);
   return buffer;
}
static int  createshmhelper(key_t k,int size,int flag)//static修饰只在本文件有效
{
  int shmid=shmget(k,size,flag);
  if(shmid==-1)//创建失败
  {
    cout<<errno<< " :" <<strerror(errno)<<endl;
       exit(2);
  }
  return  shmid;//返回共享内存标识符
}
int createshm(key_t k,int size)//创建共享内存
{
    //带有两个选项 若不存在则创建,若存在则报错
    return createshmhelper(k,size,IPC_CREAT |IPC_EXCL);
}
int getshm(key_t k,int size)
{
    //若有共享内存,则返回已有的共享内存
     return createshmhelper(k,size,IPC_CREAT );
}
char* attachshm(int shmid)//关联
{
    char*start=(char*)shmat(shmid,NULL,0);//对应类型void* 所以需要强转
     return start;
}
void detachshm(char*start)//取消关联
{
 int n=shmdt(start);
 assert(n!=-1);
 (void)n;
}
void delshm(int shmid)
{
   int n=shmctl(shmid,IPC_RMID,NULL);
   assert(n!=-1);//为-1就删除失败
   (void)n;
}
#endif 

server.cc

#include"comm.hpp"
#include<unistd.h>
int main()
{
    //1. 创建key值
  key_t k=getkey();//获取key值
  cout<<"server:"<<tohex(k)<<endl;
   //2.创建共享内存
   int shmid=createshm(k,gsize);//返回的是共享内存标识符
   cout<<"server shmid:"<<shmid<<endl;//将共享内存标识符转换为十六进制
   sleep(5);
   // 3.将自己和共享内存关联起来
   char*start=attachshm(shmid);
   //通信
   //4. 将自己和共享内存取消关联
    detachshm(start); 
   //5.删除共享内存
    delshm(shmid);
    return 0;
}

client.cc

#include"comm.hpp"
int main()
{
  key_t k=getkey();//获取key值
  cout<<"client key:"<<tohex(k)<<endl;
int shmid=getshm(k,gsize);//获取共享内存
cout<<"client shmid:"<<shmid<<endl;//将共享内存标识符转换为十六进制
  char*start=attachshm(shmid);
   detachshm(start); 
    return 0;
}

相关文章
|
15天前
|
安全 Linux Shell
Linux上执行内存中的脚本和程序
【9月更文挑战第3天】在 Linux 系统中,可以通过多种方式执行内存中的脚本和程序:一是使用 `eval` 命令直接执行内存中的脚本内容;二是利用管道将脚本内容传递给 `bash` 解释器执行;三是将编译好的程序复制到 `/dev/shm` 并执行。这些方法虽便捷,但也需谨慎操作以避免安全风险。
|
24天前
|
Linux 调度
深入理解Linux虚拟内存管理(七)(下)
深入理解Linux虚拟内存管理(七)
35 4
|
24天前
|
存储 Linux 索引
深入理解Linux虚拟内存管理(九)(中)
深入理解Linux虚拟内存管理(九)
20 2
|
24天前
|
Linux 索引
深入理解Linux虚拟内存管理(九)(上)
深入理解Linux虚拟内存管理(九)
27 2
|
24天前
|
Linux
深入理解Linux虚拟内存管理(七)(中)
深入理解Linux虚拟内存管理(七)
25 2
|
24天前
|
机器学习/深度学习 消息中间件 Unix
深入理解Linux虚拟内存管理(九)(下)
深入理解Linux虚拟内存管理(九)
16 1
|
25天前
|
Linux
深入理解Linux虚拟内存管理(七)(上)
深入理解Linux虚拟内存管理(七)
25 1
|
22天前
|
缓存 Linux 调度
Linux服务器如何查看CPU占用率、内存占用、带宽占用
Linux服务器如何查看CPU占用率、内存占用、带宽占用
71 0
|
25天前
|
Linux API
深入理解Linux虚拟内存管理(六)(下)
深入理解Linux虚拟内存管理(六)
13 0
|
25天前
|
Linux
深入理解Linux虚拟内存管理(六)(中)
深入理解Linux虚拟内存管理(六)
18 0