LinuxIPCSystemV共享内存
模型
#include
#include
#include
ftok()//获取key值
shmget()//创建/获取共享内存
shmat()//挂接共享内存
shmdt()//脱接共享内存
shmctl()//删除共享内存
ftok()
//获取key值,key值是SystemVIPC的标识符,成功返回key,失败返回-1设errno
//同pathname+同proj_id==>同key_t;
key_tftok(constcharpathname,intproj_id);
pathname:文件名
proj_id:1~255的一个数,表示project_id
key_tkey=ftok(".",100);//“.”就是一个存在且可访问的路径,100是假设的proj_id
if(-1==key)
perror("ftok"),exit(-1);
shmget()
//创建/获取共享内存,成功返回共享内存的标识符shmid,失败返回-1设errno
intshmget(key_tkey,size_tsize,intshmflg);//多设为intshmid=...和shmat()一起用比较好看
key:ftok()的返回值
size:共享内存的大小,实际会按照页的大小(PAGE_SIZE)来分配。0表示获取已经分配好的共享内存
shmflg:具体的操作标志
IPC_CREAT:若不存在则创建,需要在shmflg中"|权限信息",eg:|0664;若存在则打开
IPC_EXCL:与IPC_CREAT搭配使用,若存在则创建失败==>报错,seterrno
0:获取已经存在的共享内存
//创建sharedmemory
shmid=shmget(key,4,IPC_CREAT|IPC_EXCL|0664);
if(-1==shmid)
perror("shmget"),exit(-1);
Q:既然shmget()可以创建,那要ftok()有啥用
A:shmget才是创建共享内存,ftok()只是用来产生一个key,其实这个key的位置自己随意填一个数也可以运行,但是相对系统生成的,很容易造成冲突,所以最好用ftok产生一个key
shmat()
//挂接共享内存,成功返回映射内存的地址,失败返回(void)-1设errno
voidshmat(intshmid,constvoidshmaddr,intshmflg);
shmid:shmget()的返回值
shmaddr
NULL表示由系统选择(同mmap())
非NULL且shflg是SHM_RND,会按照页对齐的原则从shmaddr开始找最近的地址开始分配分,否则shmaddr指定的地址必须是页对齐的
shmflg:操作的标志,给0即可
SHM_RDONLY表示挂接到该共享内存的进程必须有读权限
SHM_REMAP(Linux-specific)表示如果要映射的共享内存已经有现存的内存,那么就将旧的替换
//挂接共享内存
voidpv=shmat(shmid,NULL,0);
if((void)-1==pv)
perror("shmat"),exit(-1);
shmdt()
//脱接共享内存,成功返回0,失败返回-1设errno
intshmdt(constvoidshmaddr);
//脱接shm
intres=shmdt(pv);
if(-1==res)
perror("shmdt"),exit(-1);
shmctl()
//共享内存管理,成功返回0,失败返回-1设errno
intshmctl(intshmid,intcmd,structshmid_dsbuf);
shmid:共享内存的id,由shmget()返回
buf:shmid_ds类型的指针
structshmid_ds{
structipc_permshm_perm;/Ownershipandpermissions/
size_tshm_segsz;/Sizeofsegment(bytes)/
time_tshm_atime;/Lastattachtime/
time_tshm_dtime;/Lastdetachtime/
time_tshm_ctime;/Lastchangetime/
pid_tshm_cpid;/PIDofcreator/
pid_tshm_lpid;/PIDoflastshmat(2)/shmdt(2)/
shmatt_tshm_nattch;/No.ofcurrentattaches/
...
};
//
structipc_perm{
key_t__key;/Keysuppliedtoshmget(2)/
uid_tuid;/EffectiveUIDofowner/
gid_tgid;/EffectiveGIDofowner/
uid_tcuid;/EffectiveUIDofcreator/
gid_tcgid;/EffectiveGIDofcreator/
unsignedshortmode;/Permissions+SHM_DESTandSHM_LOCKEDflags/
unsignedshort__seq;/Sequencenumber/
};
cmd
IPC_STAT表示从内核中拷贝关于这个shmid的信息到buf指向的shmid_ds中
IPC_SET将buf指向的shmid_ds的信息写入到内核的结构体中,同时更新成员shm_ctime
IPC_RMID销毁共享内存
IPC_INFO(Linux-specific)返回系统对共享内存的限制写入到buf指向的时shminfo结构体中
//_GNU_SOURCE
structshminfo{
unsignedlongshmmax;/Maximumsegmentsize/
unsignedlongshmmin;/Minimumsegmentsize;always1/
unsignedlongshmmni;/Maximumnumberofsegments/
unsignedlongshmseg;/Maximumnumberofsegmentsthataprocesscanattach;unusedwithinkernel/
unsignedlongshmall;/Maximumnumberofpagesofsharedmemory,system-wide/
};
//shmmni,shmmax,andshmall可以童工/proc里的同名文件进行修改
SHM_INFO(Linux-specific)返回一个shm_info结构体来表示该共享内存消耗的系统资源
//_GNU_SOURCE
structshm_info{
intused_ids;/#ofcurrentlyexistingsegments/
unsignedlongshm_tot;/Totalnumberofsharedmemorypages/
unsignedlongshm_rss;/#ofresidentsharedmemorypages/
unsignedlongshm_swp;/#ofswappedsharedmemorypages/
unsignedlongswap_attempts;/UnusedsinceLinux2.4/
unsignedlongswap_successes;/UnusedsinceLinux2.4/
};
SHM_STAT(Linux-specific)为IPC_STAT返回一个shmid_ds结构结构体,不同的是shmid的参数不是一个标识符,而是内核中一个包含了系统中所有共享内存信息的索引
SHM_LOCK防止系统将共享内存放到swap区,IPC_STAT读到的信息中SHM_LOCKED标记就被设置了
SHM_UNLOCK解除锁定,即允许共享内存被系统放到swap区
//使用IPC_RMID删除共享内存
intres=shmctl(shmid,IPC_RMID,NULL);
if(-1==res)
perror("shmctl"),exit(-1);
例子
//SysVIPCshm
intshmid;//定义全局变量记录id
voidfa(intsigno){
printf("deletingsharedmemories...\n");
sleep(3);//其实没用
intres=shmctl(shmid,IPC_RMID,NULL);
if(-1==res)
perror("shmctl"),exit(-1);
printf("deletesuccess\n");
exit(0);//ctrl+C已经不能结束while(1),用exit(0)来终结
}
intmain(){
//获取key
key_tkey=ftok(".",100);//.就是一个存在且可访问的路径,100是随便给的
if(-1==key)
perror("ftok"),exit(-1);
printf("key=%#x\n",key);//打印出进制的标示,即0x
//创建sharedwww.wang027.commemory
shmid=shmget(key,4,IPC_CREAT|IPC_EXCL|0664);
if(-1==shmid)
perror("shmget"),exit(-1);
printf("shmid=%d\n",shmid);
//挂接shm
voidpv=shmat(shmid,NULL,0);
if((void)-1==pv)
perror("shmat"),exit(-1);
printf("linksharedmemorysuccess\n");
//访问shm
intpi=(int)pv;
pi=100;
//脱接shm
intres=shmdt(pv);
if(-1==res)
perror("shmdt"),exit(-1);
printf("unlinksuccess\n");
//如果不再使用,删除shm
printf("删除共享内存请按CtrlC...\n");
if(SIG_ERR==signal(SIGINT,fa))
perror("signal"),exit(-1);
while(1);
return0;
}
|
|