目录
一、什么是共享内存?
二、共享内存的特点
优点
缺点
三、使用共享内存的基本函数
1、创建共享内存shmget()
2、挂接共享内存shmat
3、脱离挂接shmdt
4、共享内存控制shmctl
5.查看和删除共享内存
comm.hpp
server.cc
Client.cc
Makefile
一、什么是共享内存?
共享内存(Shared Memory)是一种高效的进程间通信(IPC)机制,允许多个进程直接访问同一块物理内存区域,实现数据的快速交换。它是IPC中速度最快的方式,因为共享内存方式的通信没有中间过程,而管道、消息队列等方式则需要将数据通过中间机制进行转换。
共享内存的原理如上图所示,主要分为两部(创内存、挂接):
1.进程在物理内存上开辟一块空间,这块空间称为共享内存。
2.不同进程将这块空间挂接到自己的进程地址空间中。
3.进程通过虚拟地址和页表的映射找到共享内存,然后对共享内存进行读写数据。
二、共享内存的特点
优点
- 高效性:共享内存是所有进程间通信方式中速度最快的,因为所有进程共享同一块内存,访问共享内存区域和访问进程独有的内存区域一样快,并不需要通过系统调用或者其它需要切入内核的过程来完成。
- 直接访问:避免了数据的各种不必要的复制,数据直接写到内存,不用若干次数据拷贝。
- 灵活性:不像匿名管道那样要求通信的进程有一定的父子关系。
缺点
- 缺乏同步机制:系统内核没有对访问共享内存进行同步,必须提供自己的同步措施。例如,在数据被写入之前不允许进程从共享内存中读取信息、不允许两个进程同时向同一个共享内存地址写入数据等。
- 生命周期:共享内存的生命周期随内核,即如果用户不使用系统调用释放它,直到操作系统关机之前它会一直存在。
- 管理复杂性:需要额外的同步机制(如信号量、互斥锁)保证数据一致性。
三、使用共享内存的基本函数
1、创建共享内存shmget()
int shmget(key_t key, size_t size, int shmflg);
参数key:这个共享内存段名字(和消息队列一样由ftok获取)size:共享内存⼤⼩(自己指定,一般为页的整数倍)shmflg:由九个权限标志构成,它们的⽤法和创建⽂件时使⽤的mode模式标志是⼀样的IPC_CREAT:创建新的共享内存IPC_CREAT|IPC_EXCL|0666:若创建的共享内存存在,报错IPC_NOWAIT:非阻塞0:如果是打开文件,写0
返回值:成功返回⼀个⾮负整数,即该共享内存段的标识码;失败返回-1
2、挂接共享内存shmat
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数shmid: 共享内存标识shmaddr:指定连接的地址(一般默认为NULL,由系统自动分配内存)shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY(连接操作用于只读内存)
返回值:成功返回⼀个指针,指向共享内存第⼀个节;失败返回-1
3、脱离挂接shmdt
int shmdt(const void *shmaddr);
参数shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段
4、共享内存控制shmctl
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数shmid:由shmget返回的共享内存标识码cmd:将要采取的动作(有三个可取值)buf:指向⼀个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1
5.查看和删除共享内存
//查看
ipcs -m
//删除
ipcrm -m id(标识)
共享内存使用案例:
分为两个进程,客户端(Client)和服务端(server)
前提介绍:
.hpp文件的作用与.h文件功能类似
.cc文件等于.cpp文件
comm.hpp
#include <iostream>
#include<stdio.h>
#include <string>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include<string.h>const std::string gpath = "/root/day5_24";
const int gid = 0x6666;
const int gshmsize = 4096;
const int gmode = 0600;
class ShareMemory
{
public:ShareMemory() : _shmid(-1), _ret(nullptr){}~ShareMemory(){}// 创建共享内存int CreateShm(){key_t key = ::ftok(gpath.c_str(), gid);if (key < 0){printf("ftok error\n");return 1;}_shmid = ::shmget(key, gshmsize, IPC_CREAT | IPC_EXCL | gmode);if (_shmid < 0){printf("shmget error\n");return 2;}return _shmid;}// 获得共享内存void GetShm(){key_t key = ::ftok(gpath.c_str(), gid);if (key < 0){printf("ftok error\n");}_shmid = ::shmget(key, gshmsize, IPC_CREAT|gmode);std::cout << "_shmid: " << _shmid << std::endl;if (_shmid < 0){printf("shmget error\n");}}// 挂地址void AttachShm(){_ret = shmat(_shmid, nullptr, 0);std::cout << "_shmid: " << _shmid << std::endl;}// 去关联void DetachShm(){int d = shmdt(_ret);if (d == -1){printf("shmdt error\n");return;}printf("shmdt success\n");}// 释放内存void DeleteShm(){shmctl(_shmid, IPC_RMID, nullptr);}void *getadder(){return _ret;}void ShmMeta(){//}private:int _shmid;void *_ret;
};ShareMemory sm;
server.cc
#include"time.hpp"
#include "Comm.hpp"
using namespace std;int main()
{sm.CreateShm();sm.AttachShm();// 在此处读出while(true){char* image=(char*)sm.getadder();std::cout << image << std::endl;sleep(1);}sm.DetachShm();sm.DeleteShm();return 0;
}
Client.cc
#include "Comm.hpp"
#include"time.hpp"
int main()
{sm.GetShm();sm.AttachShm();// 在此处写入char*image = (char*)sm.getadder();char i[] = "i am processA";while (true){strcpy(image, i);sleep(1);}sm.DetachShm();return 0;
}
Makefile
SERVER=server
CLIENT=client
CC=g++
SERVER_SRC=Server.cc
Client_SRC=Client.cc.PHONY:all
all:$(SERVER) $(CLIENT)$(SERVER):$(SERVER_SRC)$(CC) -o $@ $^ -std=c++11 -g
$(CLIENT):$(Client_SRC)$(CC) -o $@ $^ -std=c++11 -g.PHONY:clean
clean:rm -f $(SERVER) $(CLIENT)
----------------------------------------------------------------------------------------------------------------------------
本篇介绍到此结束,有问题欢迎给我评论留言。谢谢