配色: 字号:
Linux IPC System V 共享内存
2016-11-05 | 阅:  转:  |  分享 
  
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;

}

献花(0)
+1
(本文系thedust79首藏)