• 共享内存函数(shmget、shmat、shmdt、shmctl)及其范例


    摘自:https://blog.csdn.net/guoping16/article/details/6584058

    共享内存函数由shmget、shmat、shmdt、shmctl四个函数组成。下面的表格列出了这四个函数的函数原型及其具体说明。

    1.   shmget函数原型

    shmget(得到一个共享内存标识符或创建一个共享内存对象)

    所需头文件

    #include <sys/ipc.h>

    #include <sys/shm.h>

    函数说明

    得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符

    函数原型

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

    函数传入值

    key

    0(IPC_PRIVATE):会建立新共享内存对象

    大于0的32位整数:视参数shmflg来确定操作。通常要求此值来源于ftok返回的IPC键值

    size

    大于0的整数:新建的共享内存大小,以字节为单位

    0:只获取共享内存时指定为0

    shmflg

    0:取共享内存标识符,若不存在则函数会报错

    IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符

    IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个消息队列;如果存在这样的共享内存则报错

    函数返回值

    成功:返回共享内存的标识符

    出错:-1,错误原因存于error中

    附加说明

    上述shmflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行|运算来确定信号量集的存取权限

    错误代码

    EINVAL:参数size小于SHMMIN或大于SHMMAX

    EEXIST:预建立key所指的共享内存,但已经存在

    EIDRM:参数key所指的共享内存已经删除

    ENOSPC:超过了系统允许建立的共享内存的最大值(SHMALL)

    ENOENT:参数key所指的共享内存不存在,而参数shmflg未设IPC_CREAT位

    EACCES:没有权限

    ENOMEM:核心内存不足

    在Linux环境中,对开始申请的共享内存空间进行了初始化,初始值为0x00。

    如果用shmget创建了一个新的消息队列对象时,则shmid_ds结构成员变量的值设置如下:

    Ÿ        shm_lpidshm_nattachshm_atime、shm_dtime设置为0。

    Ÿ        msg_ctime设置为当前时间。

    Ÿ        shm_segsz设成创建共享内存的大小。

    Ÿ        shmflg的读写权限放在shm_perm.mode中。

    Ÿ        shm_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。

    2.   shmat函数原型

    shmat(把共享内存区对象映射到调用进程的地址空间)

    所需头文件

    #include <sys/types.h>

    #include <sys/shm.h>

    函数说明

    连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问

    函数原型

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

    函数传入值

    msqid

    共享内存标识符

    shmaddr

    指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置

    shmflg

    SHM_RDONLY:为只读模式,其他为读写模式

    函数返回值

    成功:附加好的共享内存地址

    出错:-1,错误原因存于error中

    附加说明

    fork后子进程继承已连接的共享内存地址。exec后该子进程与已连接的共享内存地址自动脱离(detach)。进程结束后,已连接的共享内存地址会自动脱离(detach)

    错误代码

    EACCES:无权限以指定方式连接共享内存

    EINVAL:无效的参数shmid或shmaddr

    ENOMEM:核心内存不足

    3.   shmdt函数原型

    shmat(断开共享内存连接)

    所需头文件

    #include <sys/types.h>

    #include <sys/shm.h>

    函数说明

    与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存

    函数原型

    int shmdt(const void *shmaddr)

    函数传入值

    shmaddr:连接的共享内存的起始地址

    函数返回值

    成功:0

    出错:-1,错误原因存于error中

    附加说明

    本函数调用并不删除所指定的共享内存区,而只是将先前用shmat函数连接(attach)好的共享内存脱离(detach)目前的进程

    错误代码

    EINVAL:无效的参数shmaddr

    4.   shmctl函数原型

    shmctl(共享内存管理)

    所需头文件

    #include <sys/types.h>

    #include <sys/shm.h>

    函数说明

    完成对共享内存的控制

    函数原型

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

    函数传入值

    msqid

    共享内存标识符

    cmd

    IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中

    IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内

    IPC_RMID:删除这片共享内存

    buf

    共享内存管理结构体。具体说明参见共享内存内核结构定义部分

    函数返回值

    成功:0

    出错:-1,错误原因存于error中

    错误代码

    EACCESS:参数cmd为IPC_STAT,确无权限读取该共享内存

    EFAULT:参数buf指向无效的内存地址

    EIDRM:标识符为msqid的共享内存已被删除

    EINVAL:无效的参数cmd或shmid

    EPERM:参数cmd为IPC_SET或IPC_RMID,却无足够的权限执行

    共享内存应用范例

    5.   父子进程通信范例

    父子进程通信范例,shm.c源代码如下:

      1 #include <stdio.h>
      2 
      3 #include <unistd.h>
      4 
      5 #include <string.h>
      6 
      7 #include <sys/ipc.h>
      8 
      9 #include <sys/shm.h>
     10 
     11 #include <error.h>
     12 
     13 #define SIZE 1024
     14 
     15 int main()
     16 
     17 {
     18 
     19     int shmid ;
     20 
     21     char *shmaddr ;
     22 
     23     struct shmid_ds buf ;
     24 
     25     int flag = 0 ;
     26 
     27     int pid ;
     28 
     29  
     30 
     31     shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0600 ) ;
     32 
     33     if ( shmid < 0 )
     34 
     35     {
     36 
     37             perror("get shm  ipc_id error") ;
     38 
     39             return -1 ;
     40 
     41     }
     42 
     43     pid = fork() ;
     44 
     45     if ( pid == 0 )
     46 
     47     {
     48 
     49         shmaddr = (char *)shmat( shmid, NULL, 0 ) ;
     50 
     51         if ( (int)shmaddr == -1 )
     52 
     53         {
     54 
     55             perror("shmat addr error") ;
     56 
     57             return -1 ;
     58 
     59  
     60 
     61         }
     62 
     63         strcpy( shmaddr, "Hi, I am child process!
    ") ;
     64 
     65         shmdt( shmaddr ) ;
     66 
     67         return  0;
     68 
     69     } else if ( pid > 0) {
     70 
     71         sleep(3 ) ;
     72 
     73         flag = shmctl( shmid, IPC_STAT, &buf) ;
     74 
     75         if ( flag == -1 )
     76 
     77         {
     78 
     79             perror("shmctl shm error") ;
     80 
     81             return -1 ;
     82 
     83         }
     84 
     85  
     86 
     87         printf("shm_segsz =%d bytes
    ", buf.shm_segsz ) ;
     88 
     89         printf("parent pid=%d, shm_cpid = %d 
    ", getpid(), buf.shm_cpid ) ;
     90 
     91         printf("chlid pid=%d, shm_lpid = %d 
    ",pid , buf.shm_lpid ) ;
     92 
     93         shmaddr = (char *) shmat(shmid, NULL, 0 ) ;
     94 
     95         if ( (int)shmaddr == -1 )
     96 
     97         {
     98 
     99             perror("shmat addr error") ;
    100 
    101             return -1 ;
    102 
    103  
    104 
    105         }
    106 
    107         printf("%s", shmaddr) ;
    108 
    109         shmdt( shmaddr ) ;
    110 
    111         shmctl(shmid, IPC_RMID, NULL) ;
    112 
    113     }else{
    114 
    115         perror("fork error") ;
    116 
    117         shmctl(shmid, IPC_RMID, NULL) ;
    118 
    119     }
    120 
    121  
    122 
    123     return 0 ;
    124 
    125 }

    编译 gcc shm.c –o shm。

    执行 ./shm,执行结果如下:

    shm_segsz =1024 bytes
    
    shm_cpid = 9503
    
    shm_lpid = 9504
    
    Hi, I am child process!

    6.   多进程读写范例

    多进程读写即一个进程写共享内存,一个或多个进程读共享内存。下面的例子实现的是一个进程写共享内存,一个进程读共享内存。

    (1)下面程序实现了创建共享内存,并写入消息。

    shmwrite.c源代码如下:

     1 #include <stdio.h>
     2 
     3 #include <sys/ipc.h>
     4 
     5 #include <sys/shm.h>
     6 
     7 #include <sys/types.h>
     8 
     9 #include <unistd.h>
    10 
    11 #include <string.h>
    12 
    13 typedef struct{
    14 
    15     char name[8];
    16 
    17     int age;
    18 
    19 } people;
    20 
    21 int main(int argc, char** argv)
    22 
    23 {
    24 
    25     int shm_id,i;
    26 
    27     key_t key;
    28 
    29     char temp[8];
    30 
    31     people *p_map;
    32 
    33     char pathname[30] ;
    34 
    35  
    36 
    37     strcpy(pathname,"/tmp") ;
    38 
    39     key = ftok(pathname,0x03);
    40 
    41     if(key==-1)
    42 
    43     {
    44 
    45         perror("ftok error");
    46 
    47         return -1;
    48 
    49     }
    50 
    51     printf("key=%d
    ",key) ;
    52 
    53     shm_id=shmget(key,4096,IPC_CREAT|IPC_EXCL|0600); 
    54 
    55     if(shm_id==-1)
    56 
    57     {
    58 
    59         perror("shmget error");
    60 
    61         return -1;
    62 
    63     }
    64 
    65     printf("shm_id=%d
    ", shm_id) ;
    66 
    67     p_map=(people*)shmat(shm_id,NULL,0);
    68 
    69     memset(temp, 0x00, sizeof(temp)) ;
    70 
    71     strcpy(temp,"test") ;
    72 
    73     temp[4]='0';
    74 
    75     for(i = 0;i<3;i++)
    76 
    77     {
    78 
    79         temp[4]+=1;
    80 
    81         strncpy((p_map+i)->name,temp,5);
    82 
    83         (p_map+i)->age=0+i;
    84 
    85     }
    86 
    87     shmdt(p_map) ;
    88 
    89     return 0 ;
    90 
    91 }

    (2)下面程序实现从共享内存读消息。

     1 shmread.c源代码如下:
     2 
     3 #include <stdio.h>
     4 
     5 #include <string.h>
     6 
     7 #include <sys/ipc.h>
     8 
     9 #include <sys/shm.h>
    10 
    11 #include <sys/types.h>
    12 
    13 #include <unistd.h>
    14 
    15 typedef struct{
    16 
    17     char name[8];
    18 
    19     int age;
    20 
    21 } people;
    22 
    23 int main(int argc, char** argv)
    24 
    25 {
    26 
    27     int shm_id,i;
    28 
    29     key_t key;
    30 
    31     people *p_map;
    32 
    33     char pathname[30] ;
    34 
    35  
    36 
    37     strcpy(pathname,"/tmp") ;
    38 
    39     key = ftok(pathname,0x03);
    40 
    41     if(key == -1)
    42 
    43     {
    44 
    45         perror("ftok error");
    46 
    47         return -1;
    48 
    49     }
    50 
    51     printf("key=%d
    ", key) ;
    52 
    53     shm_id = shmget(key,0, 0);   
    54 
    55     if(shm_id == -1)
    56 
    57     {
    58 
    59         perror("shmget error");
    60 
    61         return -1;
    62 
    63     }
    64 
    65     printf("shm_id=%d
    ", shm_id) ;
    66 
    67     p_map = (people*)shmat(shm_id,NULL,0);
    68 
    69     for(i = 0;i<3;i++)
    70 
    71     {
    72 
    73         printf( "name:%s
    ",(*(p_map+i)).name );
    74 
    75         printf( "age %d
    ",(*(p_map+i)).age );
    76 
    77     }
    78 
    79     if(shmdt(p_map) == -1)
    80 
    81     {
    82 
    83         perror("detach error");
    84 
    85         return -1;
    86 
    87     }
    88 
    89     return 0 ;
    90 
    91 }

    (3)编译与执行

    ①    编译gcc shmwrite.c -o  shmwrite。

    ②    执行./shmwrite,执行结果如下:

    key=50453281
    
    shm_id=688137

    ③    编译gcc shmread.c -o shmread。

    ④    执行./shmread,执行结果如下:

    key=50453281
    
    shm_id=688137
    
    name:test1
    
    age 0
    
    name:test2
    
    age 1
    
    name:test3
    
    age 2

    ⑤    再执行./shmwrite,执行结果如下:

    key=50453281
    
    shmget error: File exists

    ⑥    使用ipcrm -m 688137删除此共享内存。

          摘录自《深入浅出Linux工具与编程》

    7、我的练习

    write.c

     1        #include <string.h>
     2        #include <stdio.h>
     3        #include <stdlib.h>
     4        #include <sys/ipc.h>
     5        #include <sys/types.h>
     6        #include <sys/shm.h>
     7 
     8        int shmget(key_t key, size_t size, int shmflg);
     9        int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    10        void *shmat(int shmid, const void *shmaddr, int shmflg);
    11        int shmdt(const void *shmaddr);
    12 
    13 
    14 void print_buf(struct shmid_ds *buf)
    15 {
    16     printf("shm_segsz=%d==================
    ", buf->shm_segsz);
    17     printf("shm_cpid=%d
    ",      buf->shm_cpid);
    18     printf("shm_lpid=%d
    ",      buf->shm_lpid);
    19     printf("shm_atime=%d
    ",     buf->shm_atime);
    20     printf("shm_dtime=%d
    ",     buf->shm_dtime);
    21     printf("shm_ctime=%d
    ",     buf->shm_ctime);
    22     printf("shm_nattch=%d
    ",    buf->shm_nattch);
    23     printf("shm_perm.uid=%d
    ",  buf->shm_perm.uid);
    24     printf("shm_perm.gid=%d
    ",  buf->shm_perm.gid);
    25     printf("shm_perm.cuid=%d
    ", buf->shm_perm.cuid);
    26     printf("shm_perm.cgid=%d
    ", buf->shm_perm.cgid);
    27     printf("shm_perm.mode=%d
    ", buf->shm_perm.mode);
    28     printf("shm_perm.__seq=%d
    ", buf->shm_perm.__seq);
    29     printf("shm_perm.__pad1=%d
    ", buf->shm_perm.__pad1);
    30     printf("shm_perm.__pad2=%d
    ", buf->shm_perm.__pad2);
    31     printf("print======================================
    
    ");
    32 }
    33 
    34 
    35 int main(int argc ,char *argv[])
    36 {
    37     int rt = 0;
    38     int shmid = 0;
    39     void *shmaddr = NULL;
    40     struct shmid_ds buf;
    41 
    42     memset((void *)&buf, 0, sizeof(struct shmid_ds));
    43     
    44     int k = ftok("/tmp", 0x03);
    45 
    46     shmid = shmget(k, 1024, IPC_CREAT);
    47     printf("shmget k=%p(%d),shmid=%p(%d)
    ", k, k, shmid, shmid);
    48 
    49     rt = shmctl(shmid, IPC_STAT, &buf); // get
    50     printf("shmctl rt=%d
    ", rt);
    51     print_buf(&buf);
    52 
    53 
    54 
    55     shmaddr = shmat(shmid, NULL, 0);
    56     printf("shmat addr=%p
    ", shmaddr);
    57 
    58     rt = shmctl(shmid, IPC_STAT, &buf); // get
    59     printf("shmctl rt=%d
    ", rt);
    60     print_buf(&buf);
    61 
    62 
    63     strncpy(shmaddr, "GGGGGGGGGGGGGood!", 1024);
    64 
    65 
    66 
    67     rt = shmdt(shmaddr);
    68     printf("shmdt rt=%d
    ", rt);
    69     rt = shmctl(shmid, IPC_STAT, &buf); // get
    70     printf("shmctl rt=%d
    ", rt);
    71     print_buf(&buf);
    72 
    73 
    74 
    75 
    76     //rt = shmctl(shmid, IPC_RMID, NULL); // rm
    77     //printf("shmctl [RMID] rt=%d
    ", rt);
    78     //print_buf(&buf);
    79     return 0;
    80 }

    read.c

     1        #include <string.h>
     2        #include <stdio.h>
     3        #include <stdlib.h>
     4        #include <sys/ipc.h>
     5        #include <sys/types.h>
     6        #include <sys/shm.h>
     7 
     8        int shmget(key_t key, size_t size, int shmflg);
     9        int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    10        void *shmat(int shmid, const void *shmaddr, int shmflg);
    11        int shmdt(const void *shmaddr);
    12 
    13 
    14 void print_buf(struct shmid_ds *buf)
    15 {
    16     printf("shm_segsz=%d==================
    ", buf->shm_segsz);
    17     printf("shm_cpid=%d
    ",      buf->shm_cpid);
    18     printf("shm_lpid=%d
    ",      buf->shm_lpid);
    19     printf("shm_atime=%d
    ",     buf->shm_atime);
    20     printf("shm_dtime=%d
    ",     buf->shm_dtime);
    21     printf("shm_ctime=%d
    ",     buf->shm_ctime);
    22     printf("shm_nattch=%d
    ",    buf->shm_nattch);
    23     printf("shm_perm.uid=%d
    ",  buf->shm_perm.uid);
    24     printf("shm_perm.gid=%d
    ",  buf->shm_perm.gid);
    25     printf("shm_perm.cuid=%d
    ", buf->shm_perm.cuid);
    26     printf("shm_perm.cgid=%d
    ", buf->shm_perm.cgid);
    27     printf("shm_perm.mode=%d
    ", buf->shm_perm.mode);
    28     printf("shm_perm.__seq=%d
    ", buf->shm_perm.__seq);
    29     printf("shm_perm.__pad1=%d
    ", buf->shm_perm.__pad1);
    30     printf("shm_perm.__pad2=%d
    ", buf->shm_perm.__pad2);
    31     printf("print======================================
    
    ");
    32 }
    33 
    34 
    35 int main(int argc ,char *argv[])
    36 {
    37     int rt = 0;
    38     int shmid = 0;
    39     void *shmaddr = NULL;
    40     struct shmid_ds buf;
    41 
    42     memset((void *)&buf, 0, sizeof(struct shmid_ds));
    43     
    44     int k = ftok("/tmp", 0x03);
    45 
    46     shmid = 196634;
    47     //shmid = shmget(k, 0, 0);
    48     printf("shmget k=%p,shmid=%p
    ", k,shmid);
    49 
    50     rt = shmctl(shmid, IPC_STAT, &buf); // get
    51     printf("shmctl rt=%d
    ", rt);
    52     print_buf(&buf);
    53 
    54 
    55 
    56     shmaddr = shmat(shmid, NULL, 0);
    57     printf("shmat addr=%p
    ", shmaddr);
    58 
    59     rt = shmctl(shmid, IPC_STAT, &buf); // get
    60     printf("shmctl rt=%d
    ", rt);
    61     print_buf(&buf);
    62 
    63 
    64     printf("[src]=%s
    ", shmaddr);
    65 
    66 
    67     rt = shmdt(shmaddr);
    68     printf("shmdt rt=%d
    ", rt);
    69     rt = shmctl(shmid, IPC_STAT, &buf); // get
    70     printf("shmctl rt=%d
    ", rt);
    71     print_buf(&buf);
    72 
    73 
    74 
    75 
    76     //rt = shmctl(shmid, IPC_RMID, NULL); // rm
    77     //printf("shmctl [RMID] rt=%d
    ", rt);
    78     //print_buf(&buf);
    79     return 0;
    80 }
  • 相关阅读:
    韦达定理+集合运算+整体运算
    最终评审及团队事后诸葛亮作业总结
    个人作业——软件评测
    团队作业第六次—软件著作权说明书
    团队第二次作业评分总结
    团队第一次作业评分总结
    团队作业第五次—项目冲刺
    团队作业第四次—项目系统设计与数据库设计
    结对第二次作业评测总结
    团队作业第一次—团队展示
  • 原文地址:https://www.cnblogs.com/LiuYanYGZ/p/14292524.html
Copyright © 2020-2023  润新知