zoukankan      html  css  js  c++  java
  • linux shmget shmctl

    shmget
    int shmget(key_t key, size_t size, int flag);
    key: 标识符的规则
    size:共享存储段的字节数
    flag:读写的权限
    返回值:成功返回共享存储的id,失败返回-1

    key_t key
    -----------------------------------------------
        key标识共享内存的键值: 0/IPC_PRIVATE。 当key的取值为IPC_PRIVATE,则函数shmget()将创建一块新的共享内存;如果key的取值为0,而参数shmflg中设置了IPC_PRIVATE这个标志,则同样将创建一块新的共享内存。


        在IPC(InterProcess Communication)的通信模式下,不管是使用消息队列还是共享内存,甚至是信号量,每个IPC的对象(object)都有唯一的名字,称为“键”(key)。通过“键”,进程能够识别所用的对象。“键”与IPC对象的关系就如同文件名称之于文件,通过文件名,进程能够读写文件内的数据,甚至多个进程能够共用一个文件。而在IPC的通讯模式下,通过“键”的使用也使得一个IPC对象能为多个进程所共用。
        Linux系统中的所有表示System V中IPC对象的数据结构都包括一个ipc_perm结构,其中包含有IPC对象的键值,该键用于查找System V中IPC对象的引用标识符。如果不使用“键”,进程将无法存取IPC对象,因为IPC对象并不存在于进程本身使用的内存中。
        通常,都希望自己的程序能和其他的程序预先约定一个唯一的键值,但实际上并不是总可能的成行的,因为自己的程序无法为一块共享内存选择一个键值。因此,在此把key设为IPC_PRIVATE,这样,操作系统将忽略键,建立一个新的共享内存,指定一个键值,然后返回这块共享内存IPC标识符ID。而将这个新的共享内存的标识符ID告诉其他进程可以在建立共享内存后通过派生子进程,或写入文件或管道来实现。


    int size(单位字节Byte)
    -----------------------------------------------
        size是要建立共享内存的长度。所有的内存分配操作都是以页为单位的。所以如果一段进程只申请一块只有一个字节的内存,内存也会分配整整一页(在i386机器中一页的缺省大小PACE_SIZE=4096字节)这样,新创建的共享内存的大小实际上是从size这个参数调整而来的页面大小。即如果size为1至4096,则实际申请到的共享内存大小为4K(一页);4097到8192,则实际申请到的共享内存大小为8K(两页),依此类推。


    int shmflg
    -----------------------------------------------
        shmflg主要和一些标志有关。其中有效的包括IPC_CREAT和IPC_EXCL,它们的功能与open()的O_CREAT和O_EXCL相当。
        IPC_CREAT   如果共享内存不存在,则创建一个共享内存,否则打开操作。
        IPC_EXCL    只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误。

        如果单独使用IPC_CREAT,shmget()函数要么返回一个已经存在的共享内存的操作符,要么返回一个新建的共享内存的标识符。如果将IPC_CREAT和IPC_EXCL标志一起使用,shmget()将返回一个新建的共享内存的标识符;如果该共享内存已存在,或者返回-1。IPC_EXEL标志本身并没有太大的意义,但是和IPC_CREAT标志一起使用可以用来保证所得的对象是新建的,而不是打开已有的对象。对于用户的读取和写入许可指定SHM_R和SHM_W,(SHM_R>3)和(SHM_W>3)是一组读取和写入许可,而(SHM_R>6)和(SHM_W>6)是全局读取和写入许可。

    需要注意的是,使用参数要加上 | 0666 作为校验,在有些Linux系统中,如果不加此校验,则不能顺利获取共享空间的值(如Ubuntu)。此外,有两个常用参数,一般要同时出现,他们是:S_IRUSH | S_IWUSR 。由于这两个参数非常常用,程序员一般做这样的操作
      #define PERM S_IRUSR | S_IWUSR | IPC_CREAT
      这样一来,第三个参数就可以直接用PERM来表示了!

    返回值
    -----------------------------------------------
    成功返回共享内存的标识符;不成功返回-1,errno储存错误原因。
        EINVAL        参数size小于SHMMIN或大于SHMMAX。
        EEXIST        预建立key所致的共享内存,但已经存在。
        EIDRM         参数key所致的共享内存已经删除。
        ENOSPC        超过了系统允许建立的共享内存的最大值(SHMALL )。
        ENOENT        参数key所指的共享内存不存在,参数shmflg也未设IPC_CREAT位。
        EACCES        没有权限。
        ENOMEM        核心内存不足。


    struct shmid_ds
    -----------------------------------------------
        shmid_ds数据结构表示每个新建的共享内存。当shmget()创建了一块新的共享内存后,返回一个可以用于引用该共享内存的shmid_ds数据结构的标识符。

    include/linux/shm.h

        struct shmid_ds { 
            struct ipc_perm    shm_perm;      /* operation perms */ 
            int                shm_segsz;     /* size of segment (bytes) */ 
            __kernel_time_t    shm_atime;     /* last attach time */ 
            __kernel_time_t    shm_dtime;     /* last detach time */ 
            __kernel_time_t    shm_ctime;     /* last change time */ 
            __kernel_ipc_pid_t shm_cpid;      /* pid of creator */ 
            __kernel_ipc_pid_t shm_lpid;      /* pid of last operator */ 
            unsigned short     shm_nattch;    /* no. of current attaches */ 
            unsigned short     shm_unused;    /* compatibility */ 
            void               *shm_unused2; /* ditto - used by DIPC */ 
            void               *shm_unused3; /* unused */ 
        };


    struct ipc_perm
    -----------------------------------------------
        对于每个IPC对象,系统共用一个struct ipc_perm的数据结构来存放权限信息,以确定一个ipc操作是否可以访问该IPC对象。

        struct ipc_perm { 
            __kernel_key_t   key; 
            __kernel_uid_t   uid; 
            __kernel_gid_t   gid; 
            __kernel_uid_t   cuid; 
            __kernel_gid_t   cgid; 
            __kernel_mode_t mode; 
            unsigned short   seq; 
    };
    //----------------------------------------

    shmat
    void *shmat(int shmid, const void *addr, int flag);
    shmid:共享存储的id
    addr:一般为0,表示连接到由内核选择的第一个可用地址上,否则,如果flag没有指定SHM_RND,则连接到addr所指定的地址上,如果flag为SHM_RND,则地址取整
    flag:如前所述,一般为0
    返回值:如果成功,返回共享存储段地址,出错返回-1
    共享存储器的执行方式是将一个储存器区段标记为共用,这时各进程可以把这个区段映射到该进程本身的虚拟地址里。建立共享存储器可通过shmget系统调用,shmget执行后,核心程序就保留一块指定大小的空间,同时关于此共享存储器的一切数据,如区段的长度,区段的存取权,区段建立者的进程识别码等存入一个叫shmid_ds的结构。现在共享存储器虽然已经建立了,可是仍无法连上它,这时就须通过shmat系统调用得到一个指向共享存储器基址的指针,通过此指针,就可以如同于操作一般存储器似的取用共享存储器。shmdt进行相反的工作,用来脱离已连上的共享存储器。


    shmdt
    int shmdt(void *addr);
    addr:共享存储段的地址,以前调用shmat时的返回值
    shmdt将使相关shmid_ds结构中的shm_nattch计数器值减1

    当一个进程不再需要共享内存段时,它将调用shmdt()系统调用取消这个段,但是,这并不是从内核真正地删除这个段,而是把相关shmid_ds结构的 shm_nattch域的值减1,当这个值为0时,内核才从物理上删除这个共享段


    shmctl
    int shmctl(int shmid,int cmd,struct shmid_ds *buf)
    shmid:共享存储段的id
    cmd:一些命令

    IPC_STAT 得到共享内存的状态
            IPC_SET 改变共享内存的状态
            IPC_RMID 删除共享内存 

    IPC_RMID 命令实际上不从内核删除一个段,而是仅仅把这个段标记为删除,实际的删除发生在最后一个进程离开这个共享段时。 

    请注意,共享内存不会随着程序结束而自动消除,要么调用shmctl删除,要么自己用手敲命令去删除,否则永远留在系统中。

    实例:

    C代码  收藏代码
    1. #include <stdio.h>  
    2. #include <string.h>  
    3. #include <stdlib.h>  
    4. #include <errno.h>  
    5. #include <unistd.h>  
    6. #include <sys/stat.h>  
    7. #include <sys/types.h>  
    8. #include <sys/ipc.h>  
    9. #include <sys/shm.h>  
    10. #define PERM S_IRUSR|S_IWUSR  
    11.   
    12. int main(int argc,char **argv){  
    13.     int shmid;  
    14.     char *p_addr,*c_addr;  
    15.     if(argc!=2){  
    16.         fprintf(stderr,"Usage:%s a",argv[0]);  
    17.         exit(1);  
    18.     }  
    19.   
    20.     if((shmid=shmget(IPC_PRIVATE,1024,PERM))==-1){  
    21.         fprintf(stderr,"Create Share Memory Error:%s a",strerror(errno));  
    22.         exit(1);  
    23.     }  
    24.   
    25.     if(fork()){  
    26.         p_addr=shmat(shmid,0,0);  
    27.         memset(p_addr,'',1024);  
    28.         strncpy(p_addr,argv[1],1024);  
    29.         exit(0);  
    30.     }else{  
    31.         c_addr=shmat(shmid,0,0);  
    32.         printf("Client get %s",c_addr);  
    33.         exit(0);  
    34.     }  
    35. }  

     这个程序是父进程将参数写入到共享内存,然后子进程把内容读出来.最后我们要使用ip

    crm 释放资源的.先用ipcs 找出ID 然后用ipcrm shm ID 删除.

  • 相关阅读:
    【LeetCode】17. Letter Combinations of a Phone Number
    【LeetCode】16. 3Sum Closest
    【LeetCode】15. 3Sum 三个数和为0
    【LeetCode】14. Longest Common Prefix 最长前缀子串
    【LeetCode】13. Roman to Integer 罗马数字转整数
    【LeetCode】12. Integer to Roman 整型数转罗马数
    【LeetCode】11. Container With Most Water
    【LeetCode】10. Regular Expression Matching
    Models of good programmer
    RSA Algorithm
  • 原文地址:https://www.cnblogs.com/jkred369/p/6733141.html
Copyright © 2011-2022 走看看