System V 进程通信之共享内存

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liu_zhen_kai/article/details/82079605

共享内存IPC原理
共享内存是在内存中单独开辟的一段内存空间,这段内存空间有自己的数据结构,包括访问权限,空间大小和最近一次的访问时间等等,数据结构定义如下:

49 /* Data structure describing a shared memory segment.  */
 50 struct shmid_ds
 51   {
 52     struct ipc_perm shm_perm;       /* operation permission struct */
 53     size_t shm_segsz;           /* size of segment in bytes */
 54     __time_t shm_atime;         /* time of last shmat() */
 55     unsigned long int __unused1;
 56     __time_t shm_dtime;         /* time of last shmdt() */
 57     unsigned long int __unused2;
 58     __time_t shm_ctime;         /* time of last change by shmctl() */
 59     unsigned long int __unused3;
 60     __pid_t shm_cpid;           /* pid of creator */
 61     __pid_t shm_lpid;           /* pid of last shmop */
 62     shmatt_t shm_nattch;        /* number of current attaches */
 63     unsigned long int __unused4;
 64     unsigned long int __unused5;
 65   };

共享内存是用户态的空间,所以在使用共享内存传输信息的时候,不需要进行在用户态和内核态的缓冲区进行多次复制,也节省了相当一部分的时间,所以共享内存是进程间最快的通信方式。

下面来举例说明共享内存传输数据和管道传输数据的不同之处:

  • 管道
    管道在传输数据的过程中,先将相应文件复制到用户态缓冲区,在将信息从用户态缓冲区复制到内核缓冲区(管道),再将其从内核缓冲区复制到接收信息的用户进程缓冲区,再将信息复制到相应文件,一共进行4次复制操作,两次内核态与用户态之间的操作

  • 共享内存
    因为共享内存就是用户区的一块空间,直接将相应文件复制到共享内存,再将其复制到接受进程的相应文件,期间不涉及用户态与内核态的切换,也只需复制两次

Linux下共享内存管理
1.创建共享内存
函数shmget:

/* Get shared memory segment.  */
extern int shmget (key_t __key, size_t __size, int __shmflg) __THROW;
参数分析:
    key:key_t类型的key值,可自己定义或者用函数ftok创建出来
    size:开辟的共享内存的大小
    shmflg:用当识共享内存的创建标识,包括:
        IPC_CREAT:如果不存在就创建,存在则返回shmid
        IPC_EXEL:如果存在就报错返回
        IPC_NOWAIT:不等待直接返回

2.共享内存的控制
函数shmctl:

/* Shared memory control operation.  */
extern int shmctl (int __shmid, int __cmd, struct shmid_ds *__buf) __THROW;
参数分析:
    shmid:由函数shmget的返回值确定
    cmd:为要执行的参数,操作包括:
        IPC_RMID:删除共享内存
        IPC_SET:设置ipc_perm参数
        IPC_STAT:设置ipc_perm参数
        IPC_INFO:获取共享内存信息
    buf:要设置或者接收信息的载体

3.映射共享内存对象
函数shmat:

void *shmat(int shmid, const void *shmaddr, int shmflg);
参数分析:
    shmid:操作共享内存的句柄
    shmaddr:指定共享内存映射的起始地址,大于0,如果设置为0,系统会自动寻找需要映射
    的起始位置。
    shmflg:用来指定共享内存的访问权限和映射条件,包括:
        /* mode for attach */
        #define SHM_RDONLY  010000  /* read-only access */只读
        #define SHM_RND     020000  /* round attach address to SHMLBA boundary */
        #define SHM_REMAP   040000  /* take-over region on attach */
        #define SHM_EXEC    0100000 /* execution access */
        将shmflg设置为0,则默认的是有读写的权限
        返回可以传递信息的共享内存的首地址,任意类型

4.分离共享内存对象(解除映射关系)
函数shmdt:

int shmdt(const void *shmaddr);
参数分析:
    之前函数shmat返回的地址

综合运用:
实现一个动态读取写入信息的例子

写端

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <sys/ipc.h>
  5 #include <sys/shm.h>
  6 #include <string.h>
  7 #include <fcntl.h>
  8 #include <sys/wait.h>
  9 
 10 int main(int argc, char* argv[])
 11 {
 12     key_t key = ftok(argv[1], 100);
 13     int shmid = shmget(key, 128, 0664|IPC_CREAT);
 14     void* ptr = NULL;
 15 
 16     while(1){
 17         ptr = shmat(shmid, 0, 0);
 18         printf("please input >");
 19         fgets((char*)ptr, 128, stdin);
 20         fflush(stdout);
 21         fflush(stdin);
 22     }
 23 
 24     shmdt(ptr);
 25     shmctl(shmid, IPC_RMID, NULL);
 26     return 0;
 27 }
~                   

读端

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <sys/ipc.h>
  5 #include <sys/shm.h>
  6 #include <string.h>
  7 #include <fcntl.h>
  8 #include <sys/wait.h>
  9 
 10 int main(int argc, char* argv[])
 11 {
 12     key_t key = ftok(argv[1], 100);
 13     int shmid = shmget(key, 128, 0664|IPC_CREAT);
 14     void* ptr = NULL;
 15 
 16     while(1){
 17         ptr = shmat(shmid, 0, 0);
 18         printf("recive>%s", (char*)ptr);
 19         sleep(1);
 20     }
 21 
 22     shmdt(ptr);
 23     shmctl(shmid, IPC_RMID, NULL);
 24     return 0;
 25 }

这里写图片描述

猜你喜欢

转载自blog.csdn.net/liu_zhen_kai/article/details/82079605
今日推荐