• 11.1 进程间通信--共享内存


      共享内存是最快的IPC形式,一旦这样的内存映射到共享它的进程的地址空间,这些进程间的数据传递不再涉及到内核,也就是说进程不再通过执行进入内核的系统调用来传递彼此的数据。写共享内存要加锁。常和信号量在一起使用。消息队列和管道读写数据都是要进入内核的。

    示意图如下:

    传递数据的示意图如下:

    共享内存的数据结构及基本API:

    shmget函数:

      原型:int shmget(key_t  key,  size_t size,  int  shmflg)

      功能:用来创建共享内存

      参数:

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

        size:共享内存的大小

        shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的

      返回值:

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

    shmat函数:

      原型:void*  shmat(int  shmid,  const  void*  shmaddr,  int  shmflg)

      功能:将共享内存段连接到进程地址空间

      参数:

        shmid:共享内存标识

        shmaddr:指定连接的地址

        shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY

      返回值:成功返回一个指针,指向共享内存第一个字节;失败返回-1

    shmat函数(续):

      shmaddr为NULL,内核自动选择一个地址

      shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连续地址

      shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - (shmaddr  %  SHMLBA)

      shmflg为SHM_RDONLY,表示连接操作用来只读共享内存

    shmdt函数:

      原型:int shmdt(const  void*  shmaddr)

      功能:将共享内存段与当前进程脱离

      参数:

        shmaddr:由shmat所返回的指针

      返回值:成功返回0,失败返回-1

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

    shmctl函数:

      原型:int  shmctl(int shmid,  int  cmd,  struct  shmid_ds *buf)

      功能:用于控制共享内存

      参数:

        shmid:由shmget返回的共享内存标识码

        cmd:将要采取的动作,有三个可取值

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

      返回值:成功返回0,失败返回-1

    cmd的三个可选值如下:

    shmget示例程序如下:

    #include <sys/types.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <sys/msg.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    
    typedef struct 
    {
        char name[10];
        int age;
    }Teacher;
    
    int main()
    {
        int ret = 0;
        
        ret = shmget(0x2222, sizeof(Teacher), 0666);
        
        if( -1 == ret )
        {
            if(errno == ENOENT)
            {
                printf("check if shm exist 
    ");
            }
            
            perror("shmget error");
            exit(0);
        }    
        
        printf("shmget success 
    ");
        
        return 0;
    }

    最后一个参数填写0666,相当于打开共享内存,不存在的话会报错,执行结果如下:

    给最后一个参数加上创建属性,如下:

     1 #include <sys/types.h>
     2 #include <unistd.h>
     3 #include <stdio.h>
     4 #include <string.h>
     5 #include <stdlib.h>
     6 #include <errno.h>
     7 #include <sys/msg.h>
     8 #include <sys/ipc.h>
     9 #include <sys/shm.h>
    10 
    11 typedef struct 
    12 {
    13     char name[10];
    14     int age;
    15 }Teacher;
    16 
    17 int main()
    18 {
    19     int ret = 0;
    20     
    21     ret = shmget(0x2222, sizeof(Teacher), 0666 | IPC_CREAT);
    22     
    23     if( -1 == ret )
    24     {
    25         if(errno == ENOENT)
    26         {
    27             printf("check if shm exist 
    ");
    28         }
    29         
    30         perror("shmget error");
    31         exit(0);
    32     }    
    33     
    34     printf("shmget success 
    ");
    35     
    36     return 0;
    37 }

    再次执行结果如下:

    使用ipcs查看系统中的共享内存,如下:

    可以看到最后一个key值为0x2222的共享内存。

     shmat将数据写入共享内存,如下所示:

     1 #include <sys/types.h>
     2 #include <unistd.h>
     3 #include <stdio.h>
     4 #include <string.h>
     5 #include <stdlib.h>
     6 #include <errno.h>
     7 #include <sys/msg.h>
     8 #include <sys/ipc.h>
     9 #include <sys/shm.h>
    10 
    11 typedef struct 
    12 {
    13     char name[10];
    14     int age;
    15 }Teacher;
    16 
    17 int main()
    18 {
    19     int ret = 0;
    20     
    21     ret = shmget(0x2222, sizeof(Teacher), 0666 | IPC_CREAT);
    22     
    23     if( -1 == ret )
    24     {
    25         if(errno == ENOENT)
    26         {
    27             printf("check if shm exist 
    ");
    28         }
    29         
    30         perror("shmget error");
    31         exit(0);
    32     }    
    33     
    34     Teacher t1 = {"zhang", 26};
    35     
    36     Teacher *t = shmat(ret, NULL, 0);
    37     
    38     memcpy(t, &t1, sizeof(t1));
    39     pause();
    40     return 0;
    41 }

     执行结果如下:

    可以看到执行完shmat之后,这块共享内存的引用变为了1,该进程停在pause处,当进程结束时,内核自动将这个共享内存的引用计数减1,但是并不删除这块共享内存。

    当一个共享内存的引用计数大于等于2时,这时一个进程删除这块共享内存,则该共享内存的引用计数会减1,而其key值变成0,因为这个共享内存还被别的程序占用着呢。key值变成0之后,这时候再用原来的key值获取这块共享内存就不行了。这就是残缺的共享内存。当引用它的进程全退出后,这块共享内存才消失。

    读取共享内存的函数如下:

     1 #include <sys/types.h>
     2 #include <unistd.h>
     3 #include <stdio.h>
     4 #include <string.h>
     5 #include <stdlib.h>
     6 #include <errno.h>
     7 #include <sys/msg.h>
     8 #include <sys/ipc.h>
     9 #include <sys/shm.h>
    10 
    11 typedef struct 
    12 {
    13     char name[10];
    14     int age;
    15 }Teacher;
    16 
    17 int main()
    18 {
    19     int ret = 0;
    20     
    21     ret = shmget(0x2222, sizeof(Teacher), 0666 | IPC_CREAT);
    22     
    23     if( -1 == ret )
    24     {
    25         if(errno == ENOENT)
    26         {
    27             printf("check if shm exist 
    ");
    28         }
    29         
    30         perror("shmget error");
    31         exit(0);
    32     }    
    33     
    34     
    35     Teacher *t = shmat(ret, NULL, 0);
    36     
    37     printf("teacher name : %s
    ", t->name);
    38     printf("teacher age : %d
    ", t->age);
    39     
    40     
    41     return 0;
    42 }

    我们只需要根据已知的key值,先获取这块共享内存,然后将共享内存映射到读进程的地址空间,然后就可以使用这块内存了,执行结果如下:

  • 相关阅读:
    WPS JS宏
    WPS基础
    算法文章收藏
    辩论赛
    物流系统
    C#导出excel复杂表格(单元各合并)
    VUE复杂表格合并
    Linux系统创建一个npm命令行工具
    Java使用技巧记录
    Ubuntu系统安装nodejs及npm
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9434096.html
Copyright © 2020-2023  润新知