unix/linux下的共享内存、信号量、队列信息管理,在unix/linux下,经常有因为共享内存、信号量,队列等共享信息没有干净地清楚而引起一些问题。
1、ipcs 和 ipcrm 命令实例
查看共享信息的内存的命令是ipcs [-m|-s|-q]。
默认会列出共享内存、信号量,队列信息,-m列出共享内存,-s列出共享信号量,-q列出共享队列
清除命令是ipcrm [-m|-s|-q] id。
ipcrm可用来删除对应的共享内存段、信号量、消息队列;ipcrm本身只能实现单个资源的删除,利用以下命令可实现批量删除(zhangsj版权所有,呵呵):
1.ipcs -s|grep 用户名|cut -d" " -f2|xargs -n1 ipcrm -s
2.ipcs -s|awk '/用户名/{print $2}'|xargs -n1 ipcrm -s
3.ipcs -s|awk '/用户名/{system("ipcrm -s "$2)}'
4.for i in echo `ipcs|grep 用户名|cut -d" " -f2`; do ipcrm -s $i; done
-m 删除共享内存,-s删除共享信号量,-q删除共享队列。
更多参考:http://bbs.chinaunix.net/thread-1620394-1-1.html
[oracle@trade_as02 ~]$ ipcs -a
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x30024289 32768 futures 777 528384 1
0xca2fd414 491521 oracle 640 1730150400 16
------ Semaphore Arrays --------
key semid owner perms nsems
0x00028009 0 futures 666 1
0x0002800c 32769 futures 666 1
0x30024003 262146 futures 777 3
0x3002428a 294915 futures 777 2
0x3002428b 327684 futures 777 2
0x3002428c 360453 futures 777 2
0x3002428d 393222 futures 777 2
0x3002428e 425991 futures 777 2
0x52dff7d0 3964936 oracle 640 151
0x52dff7d1 3997705 oracle 640 151
0x52dff7d2 4030474 oracle 640 151
0x52dff7d3 4063243 oracle 640 151
0x52dff7d4 4096012 oracle 640 151
------ Message Queues --------
key msqid owner perms used-bytes messages
共享内存段有时不能马上删除,需使用这个内存段的所有进程向OS发送detach命令时才有释放,此时可以考虑删除进程使用的信号量,帮助释放共享内存段
2、关键知识
信号量:信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是共享内存方式的进程间通信。本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况;共享内存是运行在同一台机器上的进程间通信最快的方式,因为数据不需要在不同的进程间复制。通常由一个进程创建一块共享内存区,其余进程对这块内存区进行读写。在Linux系统下
,常用的方式是通过shmXXX函数族来实现利用共享内存进行存储的。 如Shmget,类似于 malloc函数
3、共享内存函数
由shmget、shmat、shmdt、shmctl四个函数组成。下面的表格列出了这四个函数的函数原型及其具体说明。
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_lpid、shm_nattach、shm_atime、shm_dtime设置为0。
Ÿ msg_ctime设置为当前时间。
Ÿ shm_segsz设成创建共享内存的大小。
Ÿ shmflg的读写权限放在shm_perm.mode中。
Ÿ shm_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。
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:核心内存不足 |
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 |
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,却无足够的权限执行 |