0


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

前文:
Linux–进程间的通信-匿名管道
Linux–进程间的通信–进程池
Linux–进程间的通信-命名管道

共享内存

对于两个进程,通过在内存开辟一块空间(操作系统开辟的),进程的虚拟地址通过页表映射到对应的共享内存空间中,进而实现通信

特点和作用:

  1. 高效性: 共享内存是一种高效的进程间通信方式,因为它允许多个进程直接访问同一块内存,而无需进行复制或数据传输。
  2. 快速通信: 由于共享内存直接映射到进程的地址空间,因此读写速度快,适用于对通信速度有较高要求的场景。
  3. 灵活性: 共享内存提供了一种灵活的通信方式,允许多个进程在需要时访问共享数据,而无需通过中间介质进行通信。
  4. 数据共享: 多个进程可以通过共享内存实现数据共享,从而实现对数据的共同读写和处理。

模拟实现

在这里插入图片描述
在这里插入图片描述

代码

Comm.hpp:包含共享内存的创建,销毁,挂接进程等。

#pragmaonce#include<stdio.h>#include<iostream>#include<string>#include<cerrno>#include<cstring>#include<cstdlib>#include<sys/ipc.h>#include<sys/types.h>#include<sys/shm.h>
using namespace std;constchar* pathname="/home/ubuntu/Learning/Pipe";constint proj_id=0x66;//在内核中,共享内存的基本单位是4kb,我们申请的大小相当于是n*4kbconstint DefaultSize=4096;//将key值转换为16进制的;
string ToHEX(key_t k){char buffer[1024];snprintf(buffer,sizeof(buffer),"0x%x",k);return buffer;}//获取键值key_tGetShmKeyorDie(){key_t k=ftok(pathname,proj_id);if(k<0){//当返回值为-1时,错误表示stat(2)系统调用错误
        cerr <<"ftok error, errno : "<< errno <<", error string: "<<strerror(errno)<< endl;exit(1);}return k;}//创建共享内存,只在该函数内调用intCreateShmOrDie(key_t key,int size,int flag){int shmid =shmget(key,size,flag);if(shmid<0){
        std::cerr <<"shmget error, errno : "<< errno <<", error string: "<<strerror(errno)<< std::endl;exit(2);}return shmid;}//调用时的创建共享内存intCreateShm(key_t key,int size){//如果已经存在了,那么会报错;returnCreateShmOrDie(key,size,IPC_CREAT|IPC_EXCL|0666);}//调用时的获取intGetShm(key_t key,int size){returnCreateShmOrDie(key,size,IPC_CREAT);}//删除共享内存voidDeleteShm(int shmid){int n=shmctl(shmid,IPC_RMID,nullptr);if(n<0){
        cerr<<"shmctl error"<<endl;}else{
        cout<<"shmctl delete shm success, shmid: "<<shmid<<endl;}}//查看共享内存的状态voidShmDebug(int shmid){structshmid_ds shmds;int n=shmctl(shmid ,IPC_STAT,&shmds);if(n<0){
        std::cerr <<"shmctl error"<< std::endl;return;}
    std::cout <<"shmds.shm_segsz: "<< shmds.shm_segsz << std::endl;
    std::cout <<"shmds.shm_nattch:"<< shmds.shm_nattch << std::endl;
    std::cout <<"shmds.shm_ctime:"<< shmds.shm_ctime << std::endl;
    std::cout <<"shmds.shm_perm.__key:"<<ToHEX(shmds.shm_perm.__key)<< std::endl;}void*ShmAttach(int shmid){void* addr =shmat(shmid,nullptr,0);//第二个参数设置nullptr,表示让系统选择合适的地址进行连接if((longlongint)addr==-1){
        cerr<<"shmat error"<<endl;return nullptr;}return addr;}voidShmDetach(void* addr){int n=shmdt(addr);if(n<0){
        cerr<<"shmdt error"<<endl;}}

fifo.hpp:利用管道来实现对共享内存实现同步机制。

#include<iostream>#include<string>#include<cstring>#include<cerrno>#include<sys/types.h>#include<sys/stat.h>#include<unistd.h>#include<fcntl.h>#include<assert.h>
using namespace std;#defineMode0666#definePath"./fifo"

class fifo
{
public:fifo(const string & path=Path):_path(path){umask(0);int n=mkfifo(_path.c_str(),Mode);if(n==0){
            cout<<"mkfifo success"<< endl;}else{
            cerr <<"mkfifo failed, errno: "<< errno <<", errstring: "<<strerror(errno)<< endl;}}~fifo(){int n=unlink(_path.c_str());if(n ==0){
            cout <<"remove fifo file "<< _path <<" success"<< endl;}else{
            cerr <<"remove failed, errno: "<< errno <<", errstring: "<<strerror(errno)<< endl;}}
private:
    string _path;//文件路径};

class Sync
{
public:Sync():_rfd(-1),_wfd(-1){}voidOpenReadOrDie(){
        _rfd=open(Path,O_RDONLY);if(_rfd<0)exit(1);}voidOpenWriteDie(){
        _wfd=open(Path,O_WRONLY);if(_wfd<0)exit(1);}
    bool Wait(){
        bool ret=true;uint32_t c=0;ssize_t n=read(_rfd,&c,sizeof(uint32_t));if(n==sizeof(uint32_t)){
            cout<<"server wakeup ,begin read shm..."<<endl;}elseif(n==0){
            ret=false;}else{return false;}return ret;}voidWakeup(){uint32_t c=0;ssize_t n=write(_wfd,&c,sizeof(c));assert(n==sizeof(uint32_t));

        cout<<"wakeup server..."<<endl;}~Sync(){}
private:int _wfd;int _rfd;};

ShmServer.cc

#include"Comm.hpp"#include"fifo.hpp"#include<unistd.h>intmain(){//1.获取keykey_t key =GetShmKeyorDie();
    std::cout <<"key: "<<ToHEX(key)<< std::endl;// sleep(2);//2.创建共享内存int shmid =CreateShm(key, DefaultSize);
    std::cout <<"shmid: "<< shmid << std::endl;sleep(2);//4.将共享内存与进程挂接char* addr=(char*)ShmAttach(shmid);
    cout<<"Attach shm success, addr: "<<ToHEX((uint64_t)addr)<<endl;//0.先引入管道
    fifo ff;
    Sync syn;
    syn.OpenReadOrDie();//进行通信while(1){if(!syn.Wait())break;
        cout<<"shm content: "<<addr<<endl;}ShmDetach(addr);
    std::cout <<"Detach shm success, addr: "<<ToHEX((uint64_t)addr)<< std::endl;//3.删除共享内存DeleteShm(shmid);return0;}

ShmClient.cc

#include"Comm.hpp"#include"fifo.hpp"#include<unistd.h>intmain(){key_t key =GetShmKeyorDie();
    std::cout <<"key: "<<ToHEX(key)<< std::endl;// sleep(2);int shmid =GetShm(key, DefaultSize);
    std::cout <<"shmid: "<< shmid << std::endl;char* addr=(char*)ShmAttach(shmid);
    cout<<"Attach shm success, addr: "<<ToHEX((uint64_t)addr)<<endl;//通信memset(addr,0,DefaultSize);
    Sync syn;
    syn.OpenWriteDie();for(char c ='A';c<='Z';c++){
        addr[c-'A']=c;sleep(1);
        syn.Wakeup();}ShmDetach(addr);
    std::cout <<"Detach shm success, addr: "<<ToHEX((uint64_t)addr)<< std::endl;return0;}

解释

获取键值和创建共享内存

在这里插入图片描述

如果ftok函数返回失败时,我们就需要不断的尝试,对路径名和id值进行修改,直至成功。一般来说,有几种可能:

  • 1:如果传入的路径名不存在
  • 2:传入的路径名没有读取权限,无法读取该文件的索引节点号
  • 3:文件的索引节点超过了8位,即超过了一个字节的范围
  • 4:系统中已经使用了所有的IPC键值

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

删除共享内存

在这里插入图片描述
在这里插入图片描述

查看共享内存的状态

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

挂接进程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

进入通信

在这里插入图片描述

协同机制

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

标签: linux 数据库 运维

本文转载自: https://blog.csdn.net/m0_74068921/article/details/137843706
版权归原作者 诡异森林。 所有, 如有侵权,请联系我们删除。

“Linux--进程间的通信-共享内存”的评论:

还没有评论