共享内存喜欢沙县小吃

旭日新摊子好耶!

系统从0开始搭建过通信方案,本地通信方案的代码:System V IPC

里面有共享内存、消息队列、信号量

共享内存

原理

两个进程有自己的内存区域划分,共享内存被创建出的时候是归属操作系统的,还是通过页表来映射以使用物理内存

而用地址空间进行映射让两个进程看到同一份物理内存的方式叫共享内存

所有的操作都是操作系统完成的,但是它并不知道什么时候做(决定通信的是进程)

所以OS必须提供系统调用供进程进行调用,共享内存在系统中可以同时存在多份,供不同个数,不同对进程同时进行通信,共享内存不是简单的一段内存空间,也要有描述并管理共享内存的数据结构和匹配的算法

对共享内存的管理最后要变成对链表的增删查改,共享内存 = 内存空间数据 + 内存属性

代码

怎样创建共享内存呢?

需要看一个函数捏:

第二个参数代表共享内存的大小,第三个参数代表标记位

它本质采取位图的方式传参

标志位:

IPC_CREAT:如果要创建的共享内存不存在,就创建,若存在就获取该共享内存并返回(总能获取一个)

IPC_EXCL:单独使用无意义

IPC_CREAT | IPC_EXCL:如果要创建的共享内存不存在,创建,存在则出错并返回(成功返回的一定是全新的)

有个问题:进程如何知道操作系统是否存在捏?

肯定有标识共享内存唯一性的字段,进程通过唯一性标识符发现

如果让OS自动生成这个标识符是否可行?

不行耶,进程母鸡啊

key由用户形成,只要有唯一性即可

key是用来标识共享内存唯一性的字段,是由用户设计的,有统一标准,就能一个创建,一个获取

由于我们也不知道该设定多少,所以系统为我们提供了一个随机生成key的函数:ftok

于是可以这样设计:

cpp 复制代码
#define __SHM_HPP__
#ifdef __SHM_HPP__

#include<iostream>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<cerrno>
#include<cstdio>
#include<string>

const std::string pathname = "/root/ice/pineapple/shm";
const int proj_id = 0x49;

key_t GetCommKey(const std::string &pathname,int proj_id)
{
    key_t k = ftok(pathname.c_str(),proj_id);
     if(k < 0)
     {
        perror("ftok");
     }
     return k;
}

#endif 

我们,微笑的弧度一样了!

shmget的返回值是共享内存的标识符

共享内存不随着进程的结束而释放(一直存在,直到系统重启)

要手动释放,指令或者其他系统调用

文件的生命周期随进程,而共享内存的生命周期随内核

可以这样查共享内存:

bash 复制代码
ipcs -m

想要删除这个共享内存:

bash 复制代码
ipcrm -m shmid

那key和shmid有何区别呢?

key是用户形成,内核使用的一个字段,用户不能用key进行shm的管理,是内核进行区分shm唯一性的

而shmid是内核返回给用户的一个标识符,是用来进行用户级对共享内存进行管理的id值

对上面的代码进行封装:

cpp 复制代码
#define __SHM_HPP__
#ifdef __SHM_HPP__

#include<iostream>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<cerrno>
#include<cstdio>
#include<string>

const int gCreater = 1;
const int gUser = 2;
const std::string gpathname = "/root/ice/pineapple/shm";
const int gproj_id = 0x49;
const int gShmSize = 4096;

class Shm
{
private:
key_t GetCommKey()
{
    key_t k = ftok(_pathname.c_str(),_proj_id);
     if(k < 0)
     {
        perror("ftok");
     }
     return k;
}
//创建共享内存
int ShmGet(key_t key,int size,int flag)
{
    int shmid = shmget(key,size,flag);
    if(shmid < 0)
    {
        perror("shmget");
    }
    return shmid;
}
public:
    Shm(const std::string &pathname, int proj_id,int who)
    :_pathname(pathname),_proj_id(proj_id),_who(who)
    {
        _key = GetCommKey();
        if(_who == gCreater) GetShmUserCreate();
        else if(_who == gUser) GetShmForUse();
    }
    ~Shm();

//转十六进制捏
std::string ToHex()
{
    char buffer[128];
    snprintf(buffer,sizeof(buffer),"0x%x",_key);
    return buffer;
}
bool GetShmUserCreate()
{
    if(_who == gCreater)
    {
        _shmid = ShmGet(_key,gShmSize,IPC_CREAT | IPC_EXCL);
        if(_shmid >= 0)
        {
            return true;
        }
    }
    return false;
}
bool GetShmForUse()
{
    if(_who == gUser)
    {
        _shmid = ShmGet(_key,gShmSize,IPC_CREAT);
        if(_shmid >= 0)
        {
            return true;
        }
    }
    return false;
}

private:
    key_t _key;
    int _shmid;
    std::string _pathname;
    int _proj_id;
    int _who;
};

删除共享内存老是用指令删太挫了,,,看我这招!

了解一下这个:

一个命令,标志共享内存删除

加上析构:

cpp 复制代码
#define __SHM_HPP__
#ifdef __SHM_HPP__

#include<iostream>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<cerrno>
#include<cstdio>
#include<string>
#include<unistd.h>

const int gCreater = 1;
const int gUser = 2;
const std::string gpathname = "/root/ice/pineapple/shm";
const int gproj_id = 0x49;
const int gShmSize = 4096;

class Shm
{
private:
key_t GetCommKey()
{
    key_t k = ftok(_pathname.c_str(),_proj_id);
     if(k < 0)
     {
        perror("ftok");
     }
     return k;
}
//创建共享内存
int ShmGet(key_t key,int size,int flag)
{
    int shmid = shmget(key,size,flag);
    if(shmid < 0)
    {
        perror("shmget");
    }
    return shmid;
}
public:
    Shm(const std::string &pathname, int proj_id,int who)
    :_pathname(pathname),_proj_id(proj_id),_who(who)
    {
        _key = GetCommKey();
        if(_who == gCreater) GetShmUserCreate();
        else if(_who == gUser) GetShmForUse();
    }
    ~Shm()
    {
        if(_who == gCreater)
        {
            int res = shmctl(_shmid,IPC_RMID,nullptr);
        }
        std::cout << "shm remove done ..." << std::endl;
    }

//转十六进制捏
std::string ToHex()
{
    char buffer[128];
    snprintf(buffer,sizeof(buffer),"0x%x",_key);
    return buffer;
}
bool GetShmUserCreate()
{
    if(_who == gCreater)
    {
        _shmid = ShmGet(_key,gShmSize,IPC_CREAT | IPC_EXCL);
        if(_shmid >= 0)
        {
            return true;
        }
    }
    return false;
}
bool GetShmForUse()
{
    if(_who == gUser)
    {
        _shmid = ShmGet(_key,gShmSize,IPC_CREAT);
        if(_shmid >= 0)
        {
            return true;
        }
    }
    return false;
}

private:
    key_t _key;
    int _shmid;
    std::string _pathname;
    int _proj_id;
    int _who;
};
#endif 

要完成剩下的操作,需要挂接一下:

共享内存滞销,shmat帮帮我们

shmat是将共享内存挂接到地址空间中,shmdt是取消挂接

cpp 复制代码
void *shmat(int shmid,const void *shmaddr,int shmflg); 

第一个参数是我们申请的共享内存,第二个参数是我们想挂接到哪个地址上,第三个参数指共享内存的访问权限

先写下代码:

Shm.hpp:

cpp 复制代码
#define __SHM_HPP__
#ifdef __SHM_HPP__

#include<iostream>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<cerrno>
#include<cstdio>
#include<string>
#include<unistd.h>

const int gCreater = 1;
const int gUser = 2;
const std::string gpathname = "/root/ice/pineapple/shm";
const int gproj_id = 0x49;
const int gShmSize = 4096;

class Shm
{
private:
key_t GetCommKey()
{
    key_t k = ftok(_pathname.c_str(),_proj_id);
     if(k < 0)
     {
        perror("ftok");
     }
     return k;
}
//创建共享内存
int ShmGet(key_t key,int size,int flag)
{
    int shmid = shmget(key,size,flag);
    if(shmid < 0)
    {
        perror("shmget");
    }
    return shmid;
}
std::string RoleToString(int who)
{
    if(who == gCreater)
    {
        return "Creater";
    }
    else if(who == gUser)
    {
        return "User";
    }
    else
    {
        return "None";
    }
}
public:
    Shm(const std::string &pathname, int proj_id,int who)
    :_pathname(pathname),_proj_id(proj_id),_who(who),_addrshm(nullptr)
    {
        _key = GetCommKey();
        if(_who == gCreater) GetShmUserCreate();
        else if(_who == gUser) GetShmForUse();
        _addrshm = AttachShm();
    }
    ~Shm()
    {
        if(_who == gCreater)
        {
            int res = shmctl(_shmid,IPC_RMID,nullptr);
        }
        std::cout << "shm remove done ..." << std::endl;
    }

//转十六进制捏
std::string ToHex()
{
    char buffer[128];
    snprintf(buffer,sizeof(buffer),"0x%x",_key);
    return buffer;
}
bool GetShmUserCreate()
{
    if(_who == gCreater)
    {
        _shmid = ShmGet(_key,gShmSize,IPC_CREAT | 0666);   //不用IPC_EXCL,避免在已经存在的时候出错
        if(_shmid >= 0)
        {
            return true;
        }
        std::cout << "shm create done..." << std::endl;
    }
    return false;
}
bool GetShmForUse()
{
    if(_who == gUser)
    {
        _shmid = ShmGet(_key,gShmSize,IPC_CREAT);
        if(_shmid >= 0)
        {
            return true;
        }
    }
    return false;
}
void *AttachShm()
{
    if(_addrshm != nullptr)
    {
         DetachShm(_addrshm);
    }
    void *shmaddr = shmat(_shmid,nullptr,0);  
    if(shmaddr == (void*)-1)
    {
        perror("shmat");
    }
    std::cout << "AttachShm " << RoleToString(_who) << std::endl;
    return shmaddr;
}

void DetachShm(void *shmaddr)
{
    if(shmaddr == nullptr)
    {
        return;
    }
    shmdt(shmaddr);
    std::cout << "DetachShm " << RoleToString(_who) << std::endl;
}
void *Addr()
{
    return _addrshm;
}


private:
    key_t _key;
    int _shmid;
    std::string _pathname;
    int _proj_id;
    int _who;
    void *_addrshm;
};

#endif 

server.cc:

cpp 复制代码
#include"Shm.hpp"

int main()
{
    //又是一天,什么都没有改变
    Shm shm(gpathname,gproj_id,gCreater);

    char* shmaddr = (char*)shm.Addr(); 

    while (true)
    {
        std::cout << "shm memory content: " << shmaddr <<std::endl;
        sleep(1);
    }
    
    return 0;
}

client.cc:

cpp 复制代码
#include"Shm.hpp"

int main()
{
    Shm shm(gpathname,gproj_id,gUser);
   
    char* shmaddr = (char*)shm.Addr(); 

    char ch = 'A';
    while (ch <= 'Z')
    {
        shmaddr[ch - 'A'] = ch;
        ch++;
        sleep(1);
    }
    
    return 0;
}
bash 复制代码
while :; do ipcs -m;sleep 1;done

perm表示共享内存的权限,所以我们在创建的时候应该指定一下权限

截止目前,我们是否开始通信了呢?

没有啊

我们还没通信过,之前干的都是准备工作啊亲

eeeee哈哈哈哈哈哈

呜呜呜呜

啦啦啦啦啦啦啦啦

我碎掉咯

给自己提个醒,写错过的地方:

我们需要让挂接前共享内存先清空,所以添加个接口(Shm.hpp里面Shm的成员函数)Zero:

cpp 复制代码
void Zero()
{
    if(_addrshm)
    {
        memset(_addrshm,0,gShmSize);
    }
}
cpp 复制代码
#include"Shm.hpp"

int main()
{
    Shm shm(gpathname,gproj_id,gUser);
    shm.Zero();
    char* shmaddr = (char*)shm.Addr(); 

    char ch = 'A';
    while (ch <= 'Z')
    {
        shmaddr[ch - 'A'] = ch;
        ch++;
        sleep(1);
    }
    
    return 0;
}

我现在遇到了一个问题,我刚发现我设置权限为0666了,但是共享内存的权限依旧是0,但这不是最离谱的,最离谱的是我的服务端和我的客户端都可以正常挂接上

本着遇到困难睡大觉的原则,我问了chat好几遍,调试信息也多次显示创建出的权限就是0,我真的不知道我哪里错了,所以决定在这里粘个源代码供后人嘲笑(相当于权限都是0,但是所有人可读可写可访问):

Shm.hpp:

cpp 复制代码
#define __SHM_HPP__
#ifdef __SHM_HPP__

#include<iostream>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<cerrno>
#include<cstdio>
#include<cstring>
#include<string>
#include<unistd.h>

const int gCreater = 1;
const int gUser = 2;
const std::string gpathname = "/root/ice/pineapple/shm";
const int gproj_id = 0x49;
const int gShmSize = 4096;

class Shm
{
private:
key_t GetCommKey()
{
    key_t k = ftok(_pathname.c_str(),_proj_id);
     if(k < 0)
     {
        perror("ftok");
     }
     return k;
}
//创建共享内存
// int ShmGet(key_t key,int size,int flag)
// {
//     int shmid = shmget(key,size,flag);
//     if(shmid < 0)
//     {
//         perror("shmget");
//     }
//     return shmid;
// }
std::string RoleToString(int who)
{
    if(who == gCreater)
    {
        return "Creater";
    }
    else if(who == gUser)
    {
        return "User";
    }
    else
    {
        return "None";
    }
}
public:
    Shm(const std::string &pathname, int proj_id,int who)
    :_pathname(pathname),_proj_id(proj_id),_who(who),_addrshm(nullptr)
    {
        _key = GetCommKey();
        if(_who == gCreater) GetShmUserCreate();
        else if(_who == gUser) GetShmForUse();
        _addrshm = AttachShm();
    }
    ~Shm()
    {
        if(_who == gCreater)
        {
            int res = shmctl(_shmid,IPC_RMID,nullptr);
        }
        std::cout << "shm remove done ..." << std::endl;
    }

//转十六进制捏
std::string ToHex()
{
    char buffer[128];
    snprintf(buffer,sizeof(buffer),"0x%x",_key);
    return buffer;
}
bool GetShmUserCreate()
{
    if(_who == gCreater)
    {
        _shmid = shmget(_key,gShmSize,IPC_CREAT | 0666);   //不用IPC_EXCL,避免在已经存在的时候出错
        //调试代码,我看看权限是什么,会不会是显示的问题
        struct shmid_ds shm_info;
        if (shmctl(_shmid, IPC_STAT, &shm_info) == -1) 
        {
            perror("shmctl IPC_STAT");
        } 
        else 
        {
            std::cout << "Created Shm Permissions: " << std::oct << shm_info.shm_perm.mode << std::endl;
        }
        if(_shmid >= 0)
        {
            return true;
        }
        std::cout << "shm create done..." << std::endl;
    }
    return false;
}
bool GetShmForUse()
{
    if(_who == gUser)
    {
        _shmid = shmget(_key,gShmSize,IPC_CREAT | 0666);    //哈哈,真是令人忍俊不禁
        struct shmid_ds shm_info;
        
        //调试代码,我看看权限是什么,会不会是显示的问题
        if (shmctl(_shmid, IPC_STAT, &shm_info) == -1) 
        {
            perror("shmctl IPC_STAT");
        } 
        else 
        {
            std::cout << "Created Shm Permissions: " << std::oct << shm_info.shm_perm.mode << std::endl;
        }
        
        if(_shmid >= 0)
        {
            return true;
        }
    }
    return false;
}

// // 更改共享内存权限,我先注释掉
// void SetShmPermissions(int shmid, mode_t perms)
// {
//     struct shmid_ds shm_info;
//     if (shmctl(shmid, IPC_STAT, &shm_info) == -1)
//     {
//         perror("shmctl IPC_STAT");
//         return;
//     }

//     shm_info.shm_perm.mode = perms;
//     if (shmctl(shmid, IPC_SET, &shm_info) == -1)
//     {
//         perror("shmctl IPC_SET");
//     }
// }

void *AttachShm()
{
    if(_addrshm != nullptr)
    {
         DetachShm(_addrshm);
    }
    void *shmaddr = shmat(_shmid,nullptr,0);  
    if(shmaddr == (void*)-1)
    {
        perror("shmat");
    }
    std::cout << "AttachShm " << RoleToString(_who) << std::endl;
    return shmaddr;
}

void DetachShm(void *shmaddr)
{
    if(shmaddr == nullptr)
    {
        return;
    }
    shmdt(shmaddr);
    std::cout << "DetachShm " << RoleToString(_who) << std::endl;
}

void Zero()
{
    if(_addrshm)
    {
        memset(_addrshm,0,gShmSize);
    }
}

void *Addr()
{
    return _addrshm;
}


private:
    key_t _key;
    int _shmid;
    std::string _pathname;
    int _proj_id;
    int _who;
    void *_addrshm;
};

#endif 

Server.cc:

cpp 复制代码
#include"Shm.hpp"

int main()
{
    //又是一天,什么都没有改变
    Shm shm(gpathname,gproj_id,gCreater);

    char* shmaddr = (char*)shm.Addr(); 

    while (true)
    {
        std::cout << "shm memory content: " << shmaddr <<std::endl;
        sleep(1);
    }
    
    return 0;
}

Client.cc:

cpp 复制代码
#include"Shm.hpp"

int main()
{
    Shm shm(gpathname,gproj_id,gUser);
    char* shmaddr = (char*)shm.Addr(); 

    char ch = 'A';
    while (ch <= 'Z')
    {
        shmaddr[ch - 'A'] = ch;
        ch++;
        sleep(1);
    }
    
    return 0;
}

这是一些报错信息:

《这确实是不寻常的》

要爱自己,不要为难自己

共享内存不提供对共享内存的任意保护机制,会造成数据不一致的问题

这是缺点

我们在访问共享内存的时候,没有使用系统调用

共享内存是所有进程IPC速度最快的,因为共享内存大大的减少了数据的拷贝次数

我们可以基于管道对双方进行保护:

namedPiped.hpp

cpp 复制代码
#pragma once

#include<iostream>
#include<sys/types.h>
#include<sys/stat.h>
#include<cerrno>
#include<cstdio>
#include<unistd.h>
#include<string>
#include<fcntl.h>

#define DefaultFd -1
#define Creater 1
#define User 2
#define Read O_RDONLY
#define Write O_WRONLY
#define BaseSize 4096

const std::string comm_path = "./myfifo";

class NamePiped
{
private:
    //打开文件的模式
    bool OpenNamedPipe(int mode)
    {
        _fd = open(_fifo_path.c_str(),mode);
        if(_fd < 0)
        {
            return 0;
        }
        return true;
    }
public:
    NamePiped(const std::string &path,int who)
    :_fifo_path(path), _id(who),_fd(DefaultFd)
    {
        if(_id == Creater)
        {
            int res = mkfifo(path.c_str(),0666);
            if(res != 0)
            {
              perror("mkfifo");
            }
        }
    }
    bool OpenForRead()
    {
        return OpenNamedPipe(Read);
    }
    bool OpenForWrite()
    {
        return OpenNamedPipe(Write);
    }
    
    //输出:const &:const std::string &XXX
    //输入:*      std::string *
    //输入输出:&   std::string &

    int ReadNamedPipe(std::string *out)
    {
        char buffer[BaseSize];
        int n = read(_fd,buffer,sizeof(buffer));
        if(n > 0)
        {
            //读取成功
            buffer[n] = 0;
            *out = buffer;
        }
        return n;
    }
    int WriteNamedPipe(const std::string &in)
    {
        return write(_fd,in.c_str(),in.size());
        
    }
    ~NamePiped()
    {
        if(_id == Creater)
        {
            int res = unlink(_fifo_path.c_str());
            if(res != 0)
            {
                perror("unlink");
            }
        }
        if(_fd != DefaultFd)
        {
            close(_fd);
        }
    }
private:
    const std::string _fifo_path;
    int _id;
    int _fd;
};

Shm.hpp

cpp 复制代码
#define __SHM_HPP__
#ifdef __SHM_HPP__

#include<iostream>
#include<sys/shm.h>
#include<sys/ipc.h>
#include<cerrno>
#include<cstdio>
#include<cstring>
#include<string>
#include<unistd.h>

const int gCreater = 1;
const int gUser = 2;
const std::string gpathname = "/root/ice/pineapple/shm";
const int gproj_id = 0x49;
const int gShmSize = 4096;

class Shm
{
private:
key_t GetCommKey()
{
    key_t k = ftok(_pathname.c_str(),_proj_id);
     if(k < 0)
     {
        perror("ftok");
     }
     return k;
}
//创建共享内存
// int ShmGet(key_t key,int size,int flag)
// {
//     int shmid = shmget(key,size,flag);
//     if(shmid < 0)
//     {
//         perror("shmget");
//     }
//     return shmid;
// }
std::string RoleToString(int who)
{
    if(who == gCreater)
    {
        return "Creater";
    }
    else if(who == gUser)
    {
        return "User";
    }
    else
    {
        return "None";
    }
}
public:
    Shm(const std::string &pathname, int proj_id,int who)
    :_pathname(pathname),_proj_id(proj_id),_who(who),_addrshm(nullptr)
    {
        _key = GetCommKey();
        if(_who == gCreater) GetShmUserCreate();
        else if(_who == gUser) GetShmForUse();
        _addrshm = AttachShm();
    }
    ~Shm()
    {
        if(_who == gCreater)
        {
            int res = shmctl(_shmid,IPC_RMID,nullptr);
        }
        std::cout << "shm remove done ..." << std::endl;
    }

//转十六进制捏
std::string ToHex()
{
    char buffer[128];
    snprintf(buffer,sizeof(buffer),"0x%x",_key);
    return buffer;
}
bool GetShmUserCreate()
{
    if(_who == gCreater)
    {
        _shmid = shmget(_key,gShmSize,IPC_CREAT | 0666);   //不用IPC_EXCL,避免在已经存在的时候出错
        //调试代码,我看看权限是什么,会不会是显示的问题
        struct shmid_ds shm_info;
        if (shmctl(_shmid, IPC_STAT, &shm_info) == -1) 
        {
            perror("shmctl IPC_STAT");
        } 
        else 
        {
            std::cout << "Created Shm Permissions: " << std::oct << shm_info.shm_perm.mode << std::endl;
        }
        if(_shmid >= 0)
        {
            return true;
        }
        std::cout << "shm create done..." << std::endl;
    }
    return false;
}
bool GetShmForUse()
{
    if(_who == gUser)
    {
        _shmid = shmget(_key,gShmSize,IPC_CREAT | 0666);    //哈哈,真是令人忍俊不禁
        struct shmid_ds shm_info;
        
        //调试代码,我看看权限是什么,会不会是显示的问题
        if (shmctl(_shmid, IPC_STAT, &shm_info) == -1) 
        {
            perror("shmctl IPC_STAT");
        } 
        else 
        {
            std::cout << "Created Shm Permissions: " << std::oct << shm_info.shm_perm.mode << std::endl;
        }
        
        if(_shmid >= 0)
        {
            return true;
        }
    }
    return false;
}

// // 更改共享内存权限,我先注释掉
// void SetShmPermissions(int shmid, mode_t perms)
// {
//     struct shmid_ds shm_info;
//     if (shmctl(shmid, IPC_STAT, &shm_info) == -1)
//     {
//         perror("shmctl IPC_STAT");
//         return;
//     }

//     shm_info.shm_perm.mode = perms;
//     if (shmctl(shmid, IPC_SET, &shm_info) == -1)
//     {
//         perror("shmctl IPC_SET");
//     }
// }

void *AttachShm()
{
    if(_addrshm != nullptr)
    {
         DetachShm(_addrshm);
    }
    void *shmaddr = shmat(_shmid,nullptr,0);  
    if(shmaddr == (void*)-1)
    {
        perror("shmat");
    }
    std::cout << "AttachShm " << RoleToString(_who) << std::endl;
    return shmaddr;
}

void DetachShm(void *shmaddr)
{
    if(shmaddr == nullptr)
    {
        return;
    }
    shmdt(shmaddr);
    std::cout << "DetachShm " << RoleToString(_who) << std::endl;
}

void Zero()
{
    if(_addrshm)
    {
        memset(_addrshm,0,gShmSize);
    }
}

void *Addr()
{
    return _addrshm;
}


private:
    key_t _key;
    int _shmid;
    std::string _pathname;
    int _proj_id;
    int _who;
    void *_addrshm;
};

#endif 

client.cc

cpp 复制代码
#include"Shm.hpp"
#include"namedPiped.hpp"

int main()
{
    //创建共享内存
    Shm shm(gpathname,gproj_id,gUser);
    char* shmaddr = (char*)shm.Addr(); 

    //打开管道
    NamePiped fifo(comm_path,User);
    fifo.OpenForWrite();

    char ch = 'A';
    while (ch <= 'Z')
    {
        shmaddr[ch - 'A'] = ch;
        ch++;
        std::string temp = "wakeup";
        std::cout << "add" << ch << "into Shm, " << "wakeup reader" << std::endl;

        fifo.WriteNamedPipe(temp);

        sleep(1);
    }
    
    return 0;
}

server.cc

cpp 复制代码
#include"Shm.hpp"
#include"namedPiped.hpp"

int main()
{
    //又是一天,什么都没有改变
    //创建共享内存
    Shm shm(gpathname,gproj_id,gCreater);
    char* shmaddr = (char*)shm.Addr(); 

    //创建管道
    NamePiped fifo(comm_path,Creater);
    fifo.OpenForRead();

    

    while (true)
    {
        std::string temp;
        fifo.ReadNamedPipe(&temp);
        
        std::cout << "shm memory content: " << shmaddr <<std::endl;
        sleep(1);
    }
    
    return 0;
}

共享内存的设置最好设置成4096的整数倍,如果多一点点会浪费

因为操作系统只会给你分配4096的整数倍的共享内存

怎样获取共享内存的属性捏?

cpp 复制代码
void DebugShm()
{
    struct  shmid_ds ds;
    int n = shmctl(_shmid,IPC_STAT,&ds);
    if(n < 0)
    {
        return;
    }
    std::cout << "ds.shm_perm.__key: " << ToHex(ds.shm_perm.__key) << std::endl;
    std::cout << "ds.shm_nattch: " << ds.shm_nattch << std::endl;
}

System V消息队列

原理

操作系统申请个队列,现在有两个进程:进程A+进程B,进程A可以使用消息队列的调用接口,向消息队列中放数据块,消息队列是一个进程向另一个进程发送数据块的方式,操作系统也要先描述在组织,所以不仅要有消息队列,还要有相应的属性数据

接口

那有哪些接口呢,让我们康康

cpp 复制代码
int msgget(key_t key,int msgflg);

这个接口是在获取消息队列

cpp 复制代码
key_t fork(const char *pathname,int proj_id);

消息队列使用的时候和共享内存差不多,不想用了的话就可以用msgctl捏

cpp 复制代码
int msgctl(int msqid,int cmd,struct msqid_ds *buf);

我们消息队列也有自己的属性捏

消息队列是收发结点,共享内存是挂接

发消息捏:

cpp 复制代码
int msgsnd(int msqid,const void *msgp,size_t msgsz,int msgflg);

收消息捏:

cpp 复制代码
ssize_t msgrcv(int msqid,void *msgp,size_t msgsz,long msgtyp,int msgflg);

使用消息队列需要我们自定义一个结构体,msgbuf

cpp 复制代码
struct msgbuf
{
    long mtype;        /*message type,must be > 0 */
    char mtext[1];     /*message data */
};

这个大小是自己定义的捏

发消息是这样的捏:

cpp 复制代码
#define A 1
#define B 2
struct msgbuf message;
message.mtype = B;
message.mtext = ("hello world");
msgsnd(msgid,&message,sizeof(message),0);

收消息则可以这样干:

cpp 复制代码
#define A 1
#define B 2
struct msgbuf recvbuffer;
msgrcv(msgid,&recvbuffer,sizeof(recvbuffer),A,0);
msgrcv(msgid,&recvbuffer,sizeof(recvbuffer),B,0);
指令操作

生命周期是随内核的鹅,可以这样查看消息队列:

cpp 复制代码
ipcs -q

删除的话就是:

bash 复制代码
ipcrm -q msqid

距离永远不会成为阻碍

毛豆好可爱

很好笑,下了拜拜

相关推荐
爱吃青椒不爱吃西红柿‍️2 分钟前
华为ASP与CSP是什么?
服务器·前端·数据库
IT果果日记4 分钟前
ubuntu 安装 conda
linux·ubuntu·conda
Python私教6 分钟前
ubuntu搭建k8s环境详细教程
linux·ubuntu·kubernetes
做人不要太理性9 分钟前
【C++】深入哈希表核心:从改造到封装,解锁 unordered_set 与 unordered_map 的终极奥义!
c++·哈希算法·散列表·unordered_map·unordered_set
程序员-King.17 分钟前
2、桥接模式
c++·桥接模式
羑悻的小杀马特19 分钟前
环境变量简介
linux
chnming198721 分钟前
STL关联式容器之map
开发语言·c++
程序伍六七35 分钟前
day16
开发语言·c++
小陈phd1 小时前
Vscode LinuxC++环境配置
linux·c++·vscode
运维&陈同学1 小时前
【zookeeper01】消息队列与微服务之zookeeper工作原理
运维·分布式·微服务·zookeeper·云原生·架构·消息队列