Linux 共享内存 及 利用管道实现简单协同

本文详细介绍了共享内存作为进程间通信的一种机制,包括创建共享内存的关键步骤、使用ftok和shmget函数,以及如何通过同步机制确保数据一致性。还提供了示例代码,展示了如何在客户端和服务端通过共享内存进行数据交换。
摘要由CSDN通过智能技术生成

共享内存(Shared Memory)是一种多个进程之间共享某些内存区域以进行通信的机制。这些共享的内存区域可以被多个进程访问,从而实现对进程间数据的快速交换。共享内存是最快的IPC(Inter-Process Communication,进程间通信)方式,它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程对共享内存中数据的更新。这种通信方式需要依靠某种同步机制(如信号量等)来实现进程之间的同步和互斥。


要实现共享内存:

第一步是创建一个key用于标记共享内存(通信者约定好ftok()的参数函数会返回一个相同的key)

第二部要创建共享内存,参数分别是key(上边ftok生成的key)size(共享内存的大小,推荐4KB)第三个参数是打开方式(如果你是创建就IPC_CREAT | IPC_EXCL,如果你是打开共享内存就IPC_CREAT)。

第三部关联共享内存(第一个参数传入shmget的反回值,第二个参数传nullptr表示系统帮你选择一块地址空间,第三个参数传0表示默认以读写方式打开,返回值是这块空间的起始地址,默认大小是shmget传的size)

实现自己的通信逻辑。。。

第四步取消关联:shmdt传入shmat的返回值

第五步关闭共享内存:cmd选择 IPC_RMID,buf可以传nullptr

具体实现代码:

通过对管道的read,write去控制共享内存的读写(共享内存本身不会协同)

com.hpp

#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <iostream>
#include <cstring>
#include "fifo.hpp"
using namespace std;
#define shm_size 4096
#define path "/root/110"
#define id  0x66
string TO_HEX(int num)
{
    char buffer[1024];
    snprintf(buffer,sizeof(buffer),"0X%x",num);
    return buffer;
}
key_t creatKeyorDie(const char* pathname,int proj_id)
{
    key_t n = ftok(pathname,proj_id);
    if(n==-1)
    {
        cerr<<"creatKey fail"<<endl;
    }
    return n;
}
int creatShmorDie(key_t key,size_t size,int shmflg)
{
    int n = shmget(key,size,shmflg);
    if(n==-1)
    {
        cerr<<"shmget fail"<<endl;
        exit(1);
    }
    return n;
}
int creatShm(key_t key,size_t size)
{
    //IPC_CREAT
    //IPC_EXC
    return creatShmorDie(key,size,IPC_CREAT|IPC_EXCL);
}
int getShm(key_t key,size_t size)
{

    return creatShmorDie(key,size,IPC_CREAT);
}
void DeleteShm(int shmid)
{
    int n = shmctl(shmid,IPC_RMID,nullptr);
    if(n==-1)
    {
        cerr<<"DleteShm fail"<<endl;
    }
    else
    {
        std::cout << "shmctl delete shm success, shmid: " << shmid << std::endl;
    }
}
void* shmAttach(int shmid)
{
    void* addr = shmat(shmid,nullptr,0);
    if((long long int)addr==-1)
    {
        cerr<<"Attach fail"<<endl;
        return nullptr;
    }
    return addr;
}
void shmDetach(void *addr)
{
    int n = shmdt(addr);
    if (n < 0)
    {
        std::cerr << "shmdt error" << std::endl;
    }
}

fifo.hpp

#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#define Path "./fifo"
class Fifo
{
public:
    Fifo(const std::string& path = Path):_path(path)
    {
        umask(0);
        int n = mkfifo(_path.c_str(),0666);
        if(n==-1)
        {
            std::cerr<<"mkfifo fail"<<errno<<":"<<strerror(errno)<<std::endl;
        }
        else
        {
            std::cout << "mkfifo success" << std::endl;
        }
    }
    ~Fifo()
    {
        int n = unlink(_path.c_str());
        if(n==-1)
        {
            std::cerr<<"unlink fail"<<errno<<":"<<strerror(errno)<<std::endl;
        }
        else
        {
            std::cout << "unlink success" << std::endl;
        }
    }
private:
   std::string _path;
};

class Sync
{
public: 
    Sync():wfd(-1),rfd(-1){}
    ~Sync(){}
    void openReadOrDie()
    {
        rfd = open(Path, O_RDONLY);
        if (rfd < 0)
            exit(1);
    }
    void openWriteOrDie()
    {
        wfd = open(Path, O_WRONLY);
        if (wfd < 0)
            exit(1);
    }
    bool wait()
    {
        char c;
        int n = read(rfd,&c,1);
        if(n==1)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    void wakeup()
    {
        char c;
        int n = write(wfd,&c,1);
        if(n==1)
            std::cout<<"wakeup"<<std::endl;
    }
private:
    int wfd;
    int rfd;
};

shm_client.cc

#include "com.hpp"

int main()
{
    key_t key = creatKeyorDie(path,id);
    cout<<"key_t:"<<TO_HEX(key)<<endl;

    int shmid = getShm(key,shm_size);
    cout<<"shmid:"<<shmid<<endl;

    char* buffer = (char*)shmAttach(shmid);
    cout << "Attach shm success, addr: " << TO_HEX((uint64_t)buffer) << std::endl;
    memset(buffer,0,sizeof(buffer));
    Sync syn;
    syn.openWriteOrDie();
    for(int i = 'a';i < 'z';i++)
    {
        syn.wakeup();
        buffer[i-'a'] = i;
        sleep(1);
    }

    shmDetach(buffer);
    return 0;
}

shm_server.cc

#include "com.hpp"

int main()
{
    // 1. 获取key
    key_t key = creatKeyorDie(path,id);
    std::cout << "key: " << TO_HEX(key) << std::endl;
    // sleep(2);

    // 2. 创建共享内存
    int shmid = creatShm(key, shm_size);
    std::cout << "shmid: " << shmid << std::endl;
    // sleep(2);

    // ShmDebug(shmid);
    // 4. 将共享内存和进程进行挂接(关联)
    char *addr = (char *)shmAttach(shmid);
    std::cout << "Attach shm success, addr: " << TO_HEX((uint64_t)addr) << std::endl;
    Fifo fifo;
    Sync syn;
    syn.openReadOrDie();
    // 可以进行通信了
    for(;;)
    {
        if(!syn.wait())
            break;
        sleep(1);
        cout << "shm content: " << addr << std::endl;
    }

    shmDetach(addr);
    // 3. 删除共享内存
    DeleteShm(shmid);
    return 0;
}

下面是两条命令用于查看系统中的共享内存和删除共享内存:

# ipcs -a

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      

------ Semaphore Arrays --------
key        semid      owner      perms      nsems  
ipcrm -m shmid//你要删除的共享内存的id

  • 19
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C语言扫地僧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值