当前位置:首页 » 《随便一记》 » 正文

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

2 人参与  2024年04月26日 17:35  分类 : 《随便一记》  评论

点击全文阅读


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

共享内存

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

特点和作用:

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

模拟实现

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

代码

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

#pragma once#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;const char* pathname="/home/ubuntu/Learning/Pipe";const int proj_id=0x66;//在内核中,共享内存的基本单位是4kb,我们申请的大小相当于是n*4kbconst int DefaultSize=4096;//将key值转换为16进制的;string ToHEX(key_t k){    char buffer[1024];    snprintf(buffer,sizeof(buffer),"0x%x",k);    return buffer;}//获取键值key_t GetShmKeyorDie(){    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;}//创建共享内存,只在该函数内调用int CreateShmOrDie(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;}//调用时的创建共享内存int CreateShm(key_t key,int size){    //如果已经存在了,那么会报错;    return CreateShmOrDie(key,size,IPC_CREAT|IPC_EXCL|0666);}//调用时的获取int GetShm(key_t key,int size){    return CreateShmOrDie(key,size,IPC_CREAT);}//删除共享内存void DeleteShm(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;    }}//查看共享内存的状态void ShmDebug(int shmid){    struct shmid_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((long long int)addr==-1)    {        cerr<<"shmat error"<<endl;        return nullptr;    }    return addr;}void ShmDetach(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;#define Mode 0666#define Path "./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)    {}    void OpenReadOrDie()    {        _rfd=open(Path,O_RDONLY);        if(_rfd<0)            exit(1);    }    void OpenWriteDie()    {        _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;        }        else if(n==0)        {            ret=false;        }        else        {            return false;        }        return ret;    }    void Wakeup()    {        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>int main(){        //1.获取key    key_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);    return 0;}

ShmClient.cc

#include"Comm.hpp"#include "fifo.hpp"#include<unistd.h>int main(){    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;        return 0;}

解释

获取键值和创建共享内存

在这里插入图片描述

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

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

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

删除共享内存

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

查看共享内存的状态

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

挂接进程

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

进入通信

在这里插入图片描述

协同机制

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


点击全文阅读


本文链接:http://zhangshiyu.com/post/100787.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1