六、共享内存

进程间通信IPC

  • 管道:同一机器两个进程通信
  • 套接字:不同机器两个进程通信
  • System V IPC:同一机器上多个进程间通信。包括:消息队列(频繁传递的多个消息)、信号量(进程间同步)、共享内存(内容较多的通信)。每个IPC都有一个标识符(创建返回时,内核分配)和键值(程序员选择)。

共享内存
    共享内存实际上是一段特殊的内存区域,这一段区域可以被多个进程映射到自身的地址空间中。多个进程就可以操作自身的这块区域来共同操作共享内存。每块共享内存在内核中实际上是以一个虚拟的文件存在的,这个文件代表一块内存区域。如果有进程连接共享内存,实际上是映射这一个虚拟的文件。
    Linux创建进程时,有很大的虚拟地址空间,一小部分存放代码、数据、堆和栈,剩余的初始化为空闲。一块共享内存一旦被连接,即被映射到空闲虚拟地址空间。随后进程就可以像对待普通内存区那样读写共享内存。

共享内存的系统调用
- 头文件在linux/include/linux/下
- 源文件在linux/ipc/下

#include <sys/type.h>
#include <sys/ipc.h>
#include <sys/shm.h>
//创建一块共享内存,或返回一个已存在共享内存id
//返回的id是个数组下标,这个数组管理着所有共享内存
int shmget(key_t key, int size, int shmflg);
//将一块共享内存映射到一个进程的地址空间
void *shmat(int shmid, char *shmaddr, int shmflg);
//取消一个进程共享内存的映射
void *shmdt(int *shmaddr);
//对共享内存的各种操作,如设置所有者,读写权限,或者销毁其中一块共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

键值
键值的作用如同文件的文件名,每个IPC对象并不存在进程本身使用的内存中,创建IPC时根据键值返回其ID。shmget函数的第一个参数key可以是一块已经存在共享内存的键值、0、或IPC_PRIVATE。内存分配以页为单位,如果进程申请一块只有一个字节的内存,内存管理器也会分配一页4KB。

数据结构

  • linux/include/linux/shm.h
  • Linux内核中,每个共享内存用shmid_ds结构表示
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 */
};
  • 每个IPC对象用一个ipc_perm结构存放权限信息
  • linux/include/linux/ipc.h
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;
};

和系统调用fork、exec、exit之间的关系
- fork之后,子进程继承父进程已连接的共享内存
- exec之后,所有已连接的共享内存被分离,但不被销毁
- exit,所有已连接的共享内存被分离,但不被销毁
- 目前没有方法来确保进程互斥访问共享内存,因此使用共享内存机制进行通信时的互斥问题,必须由用户自己解决。

猜你喜欢

转载自blog.csdn.net/qq_23084801/article/details/78764701