zoukankan      html  css  js  c++  java
  • Linux IPC实践(9) --System V共享内存

    共享内存API

    #include <sys/ipc.h>
    #include <sys/shm.h>
    
    int shmget(key_t key, size_t size, int shmflg);
    void *shmat(int shmid, const void *shmaddr, int shmflg);
    int shmdt(const void *shmaddr);
    int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    //System V 共享内存基本数据结构
    struct shmid_ds
    {
        struct ipc_perm shm_perm;    /* Ownership and permissions: System V IPC所共有的数据结构 */
        size_t          shm_segsz;   /* Size of segment (bytes): 共享内存段的大小 */
        time_t          shm_atime;   /* Last attach time */
        time_t          shm_dtime;   /* Last detach time */
        time_t          shm_ctime;   /* Last change time */
        pid_t           shm_cpid;    /* PID of creator */
        pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
        shmatt_t        shm_nattch;  /* No. of current attaches */
        ...
    };

    shmget

    int shmget(key_t key, size_t size, int shmflg);

       创建共享内存,并将该内存的内容初始化为0

       打开一个已经存在共享内存, 如果打开时不知道共享内存的大小, 可以将size指定为0, shmflg可以指定为0(按照默认的权限打开);    

    参数:

       key:这个共享内存段名字;

       size:共享内存大小(bytes);

       shmflg:用法类似msgget中的msgflg参数;

    返回值:

       成功返回一个非负整数,即该共享内存段的标识码;失败返回-1

    /**示例: 创建并打开一个共享内存 **/
    int main(int argc,char **argv)
    {
        const int SHM_SIZE = 1024;
        int shmid = shmget(0x1234, SHM_SIZE, 0666|IPC_CREAT);
        if (shmid == -1)
            err_exit("shmget error");
        cout << "share memory get success" << endl;
    }

    shmat

    void *shmat(int shmid, const void *shmaddr, int shmflg);

       连接到本进程地址空间, 成功连接之后, 对该内存的操作就与malloc来的一块内存非常类似了, 而且如果这块内存中有数据, 则就可以直接将其中的数据取出来!!

    参数:

       shmaddr:指定连接的地址(推荐使用NULL)

       shmflg:一般指定为0, 表示可读,可写; 而它的另外两个可能取值是SHM_RND和SHM_RDONLY(见下)

    返回值:

       成功返回一个指针,指向共享内存起始地址;失败返回(void *) -1


    shmaddr与shmflg组合说明

    shmaddr为NULL

    Linux内核自动为进程连接到进程的内存(推荐使用)

    shmaddr不为NULL且shmflg无SHM_RND标记

    以shmaddr为连接地址

    shmaddr不为NULL且shmflg设置了SHM_RND标记

    连接的地址会自动向下调整为SHMLBA的整数倍;

    公式:shmaddr - (shmaddr % SHMLBA)

    SHMLBA为内存页面的大小(4K)

    shmflg=SHM_RDONLY

    只读共享内存, 不然的话就是可读,可写的, 注意: 此处没有可读,可写这个概念

     

    shmdt

    int shmdt(const void *shmaddr);

    参数:

       shmaddr: 由shmat所返回的指针

    注意:将共享内存段与当前进程脱离不等于删除共享内存段

    /** 示例: 将数据写入/读出共享内存
    程序write: 将数据写入共享内存
    程序read: 将数据读出共享内存(当然, 可以读取N多次)
    **/
    //write程序
    struct Student
    {
        char name[26];
        int age;
    };
    int main(int argc,char **argv)
    {
        int shmid = shmget(0x1234, sizeof(Student), 0666|IPC_CREAT);
        if (shmid == -1)
            err_exit("shmget error");
    
        // 以可读, 可写的方式连接该共享内存
        Student *p = (Student *)shmat(shmid, NULL, 0);
        if (p == (void *)-1)
            err_exit("shmat error");
        strcpy(p->name, "xiaofang");
        p->age = 22;
        shmdt(p);
    }
    //read程序
    int main(int argc,char **argv)
    {
        int shmid = shmget(0x1234, 0, 0);
        if (shmid == -1)
            err_exit("shmget error");
    
        // 以只读方式连接该共享内存
        Student *p = (Student *)shmat(shmid, NULL, 0);
        if (p == (void *)-1)
            err_exit("shmat error");
    
        // 直接将其中的内容打印输出
        cout << "name: " << p->name << ", age: " << p->age << endl;
        shmdt(p);
    }

    shmctl

    int shmctl(int shmid, int cmd, struct shmid_ds *buf);

    设置/获取共享内存属性

    参数:

       cmd:将要采取的动作(三个取值见下)

       buf:指向一个保存着共享内存的模式状态和访问权限的数据结构

    System V共享内存小结:

       1.共享内存被别的程序占用,则删除该共享内存时,不会马上删除(引用计数计数);

       2.此时会出现一个现象:该共享内存的key变为0x00000000,变为私有;

       3.此时还可以读,但必须还有办法获取该共享内存的ID(shmid),因为此时试图通过该共享内存的key获取该共享内存,是白费的!

    /** 示例: 删除共享内存 **/
    int main(int argc,char *argv[])
    {
        int shmid = shmget(0x1234, 0, 0);
        if (shmid == -1)
            err_exit("shmget error");
    
        if (shmctl(shmid, IPC_RMID, NULL) == -1)
            err_exit("shmctl IPC_RMID error");
        cout << "share memory remove success" << endl;
    }

  • 相关阅读:
    常见的JedisConnectionException 异常
    使用jstack分析解决进程死锁问题
    微信支付(java版本)_统一下单
    使用Quartz任务调用的时候报错Based on configured schedule, the given trigger will never fire.
    什么是localStorage、sessionStorage,与cookie的区别?
    JavaScript for循环、数组高级语法
    SpringBoot集成Swagger2
    SpringMVC全局异常处理,看这一篇就够了
    SpringMVC文件上传的三种方法
    HDU 2089 不要62 数位dp
  • 原文地址:https://www.cnblogs.com/itrena/p/5926958.html
Copyright © 2011-2022 走看看