一、共享内存
使用一块共享内存的过程:
由一个进程分配;
需要访问这个共享内存段的每一个进程都将这个共享内存绑定到自己的地址空间中;
完成通信后,所有进程则将共享内存与自己的地址空间分离开来;
由一个进程释放该共享内存段。
Linux每个进程都维护一个从物理页面地址到虚拟页面地址之间的映射。
分配共享内存就是由内核分配一或多个新的内存页面。一个进程如需使用这个共享内存段,则必须建立进程本身的虚拟地址到共享内存页面地址之间的映射,该过程称为绑定。当对共享内存的使用结束之后,解除这个映射关系,该过程称为分离。
内核为每个共享内存段设置了一个shmid_ds结构用以管理共享内存
shmatt_t是一个至少比unsigned short更大的整数类型.
1、shmget函数
分配一个共享内存段.
key 用于标识一个共享内存的键,通常为一整数。
size 共享内存的字节数,常向上取整到PAGE_SIZE的整数倍。
shmflg 标志位,低9位用于指定访问权限。IPC_CREAT表示创建信号 量集,可按位或IPC_EXCL。
返回值 成功时,返回共享内存的标识符(一个非负整数)。出错时, 返回-1并设置errno。常见的错误值如下:
EACCES 无访问权限
EEXIST 在同时指定IPC_CREAT和IPC_EXCL时,具有指定键的信号量集 已存在.
EINVAL size小于SHMMIN或大于SHMMAX,或key所指共享内存已存在, 但size比已存在的共享内存更大.
ENOENT 键不存在.
2、shmat函数
将共享内存绑定到当前进程的内存空间.
shmid 由shmget返回的标识符.
shmaddr 绑定的地址(本进程地址空间的地址).
shmflg 标志位,常用的值为SHM_RND和SHM_RDONLY.
返回值 对于shmat,成功时返回共享内存的地址;出错时,返回 (void*)-1并设置errno。
说明
如果shmaddr指定为NULL,系统将选择一个合适的地址来绑定共享内存。这是推荐的做法。
如果shmaddr不为NULL,shmflg指定了SHM_RND,则实际绑定地址为shmaddr 向下舍入到最近的SHMLBA(=PAGE_SIZE)的倍数的位置。目前,Linux下SHMLBA等于PAGE_SIZE(内存页面大小)。
如果shmaddr不为NULL,shmflg未指定了SHM_RND,shmaddr必须为一页对齐(即页面大小的整数倍)的地址。
如果shmflg指定了SHM_RDONLY,则共享内存以只读的方式绑定到本进程的地址空间,否则为“读写”方式。
shmat成功时更改与共享内存关联的shmid_ds 结构,将其shm_atime成员 设置为当前时间,shm_lpid成员设置为当前进程的PID,shm_nattch成员的值则增1。
3、shmdt函数
将已绑定的共享内存与当前进程的内存空间相分离。
shmaddr 绑定的地址(本进程地址空间的地址)
返回值 成功时返回0,失败时返回-1并设置errno
说明
shmdt如果成功也会更改与共享内存关联的shmid_ds 结构,将其shm_dtime成员设置为当前时间,shm_lpid成员设置为当前进程的PID,shm_nattch成员的值则减1。
如果shm_nattch的值变成了0,且共享内存段标记为删除,则相应的共享内存段被删除。
用fork创建的子进程将继承已绑定的共享内存段。但在子进程中调用exec系列函数后,所有已绑定的共享内存段会与新进程分离。
当进程调用_exit函数退出的时候,所有已绑定的共享内存段也会自动从进程分离出去。
4、shmctl函数
可对共享内存进行多种类型的控制。
shmid 由shmget返回的标识符
cmd 要执行的动作
buf 用于设置(cmd为IPC_SET)或获取(cmd为IPC_STAT) 共享内存段的信息
返回值 成功时返回非负数,失败时返回-1并设置errno
说明
常用的cmd命令是IPC_RMID,用于删除一个共享内存段。
在进程中调用 exit 和 exec 会使进程分离共享内存段,但不会删除这个内存段。在结束使用每个共享内存段的时候都应当使用 shmctl的IPC_RMID命令进行释放。
二、消息队列
消息队列独立于发送和接收进程而存在。消息队列和队列中的内容保留在文件系统中。
内核为每个消息队列设置了一个shmid_ds结构用以管理消息队列。
1、msgget函数
创建或获取一个消息队列.
key 用于标识一个消息队列的键,通常为一整数。
msgflg 标志位,低9位用于指定访问权限。IPC_CREAT表示创建信 号量集,可按位或IPC_EXCL。
返回值 成功时,返回消息队列的标识符(一个非负整数)。出错时, 返回-1并设置errno。常见的错误值如下:
EACCES 无访问权限.
EEXIST 在同时指定IPC_CREAT和IPC_EXCL时,具有指定键的消息队列 已存在.
ENOENT 键不存在.
说明
调用msgget函数时,参数msgflg指定IPC_CREAT而未指定IPC_EXCL,如果具有指定键的消息队列已存在,则只是忽略创建动作,而不会出错。
2、msgsnd函数
把一条消息添加到消息队列中。
msqid 由msgget返回的消息队列标识符
msgp 指向要发送的消息的缓冲区的指针
msgsz 消息长度。这个长度不包括长整形成员变量的长度。
msgflg 标志。指定IPC_NOWAIT时,表示当队列满或达到系统限制 时,函数立即返回(返回值为-1 ),不发送消息。
返回值 成功时返回0;失败时返回-1,并设置errno变量。
说明
未指定IPC_NOWAIT时, 如果队列满或达到系统限制,函数返回-1,错误为EAGAIN。
3、msgrcv函数
从一个消息队列获取消息
msqid 由msgget返回的消息队列标识符
msgp 指向准备接收消息的缓冲区的指针
msgsz 消息长度。这个长度不包括长整形成员变量的长度。msgp所 指向的缓冲区应大于或等于此长度。
msgtyp 一个长整数,可能情况:
若值为0,获取队列中的第一个可用消息;
若值大于0,获取具有相同类型的第一个消息;
若小于0,获取消息类型小于或等于其绝对值的第一个消息。
msgflg 标志。指定IPC_NOWAIT时,表示当没有相应类型消息时,函数立即返回(返回值为-1 ),不接收消息,errno设置为:ENOMSG
返回值 成功时返回0;失败时返回-1,并设置errno变量。
4、msgctl函数
直接控制消息队列,可对消息队列做多种操作.
msqid 由msgget返回的消息队列标识符.
cmd 要采取的动作,常取以下值:
IPC_STAT 将内核所管理的消息队列的当前属性值复制到buf(msqid_ds结 构)中.
IPC_SET 如果进程有足够的权限,就把内核所管理的消息队列的当前属性 值设置为buf(msgqid_ds结构)各成员的值
IPC_RMID 删除消息队列.
buf 缓冲区,作用视cmd而定.
return value 成功时返回0;失败时返回-1,并设置errno变量。
说明
如果在进程正阻塞于msgsnd或msgrcv中等待时删除消息队列,则这两个函数将以失败返回。