zoukankan      html  css  js  c++  java
  • UNIX环境下的共享内存

      好久没更新博客了,最近几个月一直在忙项目,现在终于有时间进一步学习了。这次记录的是unix环境中共享内存的使用方法。

      

     在我理解,共享内存就是在内存中开辟一段空间,各个毫不相干的进程就可以通过访问这段内存中的资源,从而达到进程间通信的效果。由于是对同一块内存进行操作,没有涉及到资源的复制等操作,所以在IPC对象中共享内存速度和效率都是很高的。
         使用共享内存过程中需要的函数
         1、shmget
         该函数通过键值向内核申请一块共享内存
         函数原型:int  shmget(key_t key, size_t size, int shmflg);
         其中,key是每一个IPC结构都需要的键值;size是想要获取共享内存的大小,单位是字节;shmflag是获取共享内存的标志,一般为IPC_CREAT,当该key值对应的共享内存不存在时创建之,存在的话就打开。当创建共享内存时,还应添加创建共享内存的权限,如IPC_CREAT | 0666。该函数成功返回时得到共享内存的标示符,失败返回-1。
         2、shmat
         该函数将已申请到的共享内存连接到用户进程空间中
         函数原型:void * shmat(int shmid, const void *shmaddr, int shmflg);
         其中,shmid是共享内存的标识符;shmaddr指明将该内存映射到进程空间哪一块儿区域,推荐将其置NULL,由linux内核自动分配;flag为连接到进程空间时的权限选项,一般填0。该函数成功返回时返回该共享内存的首地址,失败返回-1。
         3、shmdt
         该函数将连接到用户进程的共享内存与进程分离
         函数原型:int shmdt(const void *shmaddr);
         其中,shmaddr为要分离的共享内存的首地址。成功返回0,失败返回-1。
         4、shmctl
         该函数用于控制得到的共享内存
         函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
         内存中每一段共享内存都对应一个shmid_ds结构体用来维护。其中,cmd是要对shmid指向的共享内存执行的操作。当cmd为IPC_STAT时,取出shmid指向的共享内存对应的shmid_ds结构,并存储到buf中。当cmd为IPC_RMID时,删除shmid指向的共享内存段,此时buf填0。
     
      
    ======================分割线================================
     
         下面写两个程序来演示共享内存的使用方法。设计思路:write进程打开共享内存,并向其中循环写入数据,每次写完后等待read进程将其读走,再进行下一次写入。当write进程写入end时,两个进程都终止。贴代码: 
    /*write.c*/
    #include <sys/ipc.h> #include <sys/shm.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> /*共享内存中缓冲区的大小*/ #define BUFFER_SIZE 2048 struct temp { int write_flag; char share_buffer[BUFFER_SIZE] }; int main(int argc, char const *argv[]) { int shmid; /*循环开关*/ int running = 1; char buffer[BUFFER_SIZE]; struct temp *share_temp; /*合成键值*/ key_t key = ftok(".", 2); /*打开共享内存*/ if((shmid = shmget(key, sizeof(struct temp), IPC_CREAT)) == -1) { printf("memory get failed "); exit(EXIT_FAILURE); } printf("shmid is %d ", shmid); /*映射共享内存*/ if((share_temp = shmat(shmid, NULL, 0)) == (void *)-1) { printf("memory at failed "); exit(EXIT_FAILURE); } /*循环写入数据*/ while(running) { while(share_temp->write_flag) { sleep(1); printf("wait for read process "); } fgets(buffer, BUFFER_SIZE, stdin); strncpy(share_temp->share_buffer, buffer, BUFFER_SIZE); share_temp->write_flag = 1; if(strncmp(share_temp->share_buffer, "end", 3) == 0) running = 0; } /*分离共享内存*/ if((shmdt((void *)share_temp)) == -1) { printf("memory fenli failed "); exit(EXIT_FAILURE); } return 0; }
    /*read.c*/
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    /*共享内存中缓冲区的大小*/
    #define BUFFER_SIZE 2048
    
    struct temp
    {
        int write_flag;
        char share_buffer[BUFFER_SIZE]
    };
    
    int main(int argc, char const *argv[])
    {
        int shmid;
    
        /*循环开关*/
        int running = 1;
    
        struct temp *share_temp;
    
        key_t key = ftok(".", 2);
    
        /*创建共享内存*/
        if((shmid = shmget(key, sizeof(struct temp), IPC_CREAT|0666)) == -1)
        {
            printf("memory get failed
    ");
            exit(EXIT_FAILURE);
        }
    
        printf("shmid is %d
    ", shmid);
    
        /*映射共享内存*/
        if((share_temp = shmat(shmid, NULL, 0)) == (void *)-1)
        {
            printf("memory at failed
    ");
            exit(EXIT_FAILURE);
        }
    
        /*循环读取数据*/
        while(running)
        {
            if(share_temp->write_flag)
            {
                printf("write is %s
    ", share_temp->share_buffer);
                share_temp->write_flag = 0;
            }
    
            if(strncmp(share_temp->share_buffer, "end", 3) == 0)
                running = 0;
        }
    
        /*分离共享内存*/
        if((shmdt((void *)share_temp)) == -1)
        {
            printf("memory fenli failed
    ");
            exit(EXIT_FAILURE);
        }
    
        /*删除共享内存*/
        if((shmctl(shmid, IPC_RMID, 0)) == -1)
        {
            printf("memory delete failed
    ");
            exit(EXIT_FAILURE);
        }
    
        return 0;
    }

      下面说说写程序过程中遇到的问题:开始用普通用户执行read程序,创建共享内存的时候没有加上0666选项,结构返回错误信息memory at failed,即连接到进程空间失败,切换到root用户再执行就可以。一开始还以为linux歧视普通用户,不让普通用户使用共享内存。后来发现创建的时候加上权限0666就可以了,其他IPC对象也同理。

      如果有疑问或错误,欢迎指出。

     
  • 相关阅读:
    71 是否同一棵二叉搜索树(25 分)
    75 平衡二叉树的根(25 分)
    72 树种统计(25 分)
    2018(容斥定理 HDU6286)
    直观的理解计算机中的数值编码
    如何关闭emacs开启时自己打开的欢迎界面
    图论:最短路径:广度优先搜索(C语言实现)
    ubunut 14.04 将Caps Lock设置为Control
    邻接表:C语言实现
    队列(C语言实现)
  • 原文地址:https://www.cnblogs.com/51qianrushi/p/4547564.html
Copyright © 2011-2022 走看看