内核为每个共享存储段设置了一个shmid_ds结构
struct shmid_ds{
struct ipc_perm shm_perm; /*操作权限*/
int shm_segsz; /*段的大小(以字节为单位)*/
time_t shm_atime; /*最后一个进程附加到该段的时间*/
time_t shm_dtime; /*最后一个进程离开该段的时间*/
time_t shm_ctime; /*最后一个进程修改该段的时间*/
unsigned short shm_cpid; /*创建该段进程的pid*/
unsigned short shm_lpid; /*在该段上操作的最后1个进程的pid*/
short shm_nattch; /*当前附加到该段的进程的个数*/
unsigned short shm_npages; /*段的大小(以页为单位)*/
unsigned long *shm_pages; /*指向frames->SHMMAX的指针数组*/
struct vm_area_struct *attaches; /*对共享段的描述*/
};
在IPC中,我们经常用用key_t的值来创建或者打开信号量,共享内存和消息队列。通常情况下,该id值通过ftok函数得到
#include <sys/types.h> #include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id); 返回值:成功返回key_t值,失败返回-1
1)pathname一定要在系统中存在并且进程能够访问的,一般使用当前目录,如:
key_t key;
key = ftok(".", 1); 这样就是将fname设为当前目录。
2)proj_id是一个1-255之间的一个整数值,典型的值是一个ASCII值。
调用函数shmget获得一个共享存储表示符
#include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg); 返回值:成功返回共享存储ID,出错返回-1参数size是共享存储段的长度.通常将其向上取为系统页长的整数倍。如果创建一个新段必须指定size,引用现存的段则size指定为0
shmflg参数:
0:取共享内存标识符,若不存在则函数会报错
IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符
IPC_CREAT|IPC_EXCL:如果内核中不存在键值 与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错
用户读 0400
用户写 0200
组读 0040
组写 0020
其他读 0004
其他写 0002
一旦创建了一个共享存储段,进程就可调用shmat将其链接到它的地址空间,shmdt取消链接
#include <sys/types.h> #include <sys/shm.h> void *shmat(int shmid, const void *shmaddr, int shmflg); 返回值:成功返回共享内存地址,出错返回-1 int shmdt(const void *shmaddr); 返回值:成功返回0,出错返回-1若addr为0,则由内核选择第一个可用地址
shmctl函数对共享存储段执行多种操作
#include <sys/ipc.h> #include <sys/shm.h> int shmctl(int shmid, int cmd, struct shmid_ds *buf); 返回值:成功返回0,出错返回-1cmd参数指定下列5种命令中的一种,使其在shmid指定的段上执行
IPC_STAT 取此段的shmid_ds结构,并放在buf指向的结构中 IPC_SET 按buf指向的结构中的值设置与此段相关结构中下列三个段:shm_perm.uid shm_perm.gid shm_perm.mode IPC_RMID 从系统中删除共享存储段 Linux和Solaris提供了另外两种命令,此命令只能由超级用户执行 SHM_LOCK 将共享存储段锁在内存中。 SHM_UNLOCK 解锁共享存储段。
多进程通信简单示例:
进程A
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/shm.h>
#include <sys/ipc.h>
key_t key;
int shmid;
int *p;
int i=0;
void deal(int s)
{
if(s==SIGINT)
{
//4.卸载共享内存shmdt
shmdt(p);
//5.删除共享内存shctl
shmctl(shmid,IPC_RMID,0);
exit(0);
}
}
main()
{
signal(SIGINT,deal);
//1.创建共享内存shmget
key=ftok(".",255);
if(key==-1) printf("ftok error:%m\n"),exit(-1);
shmid=shmget(key,4,IPC_CREAT|IPC_EXCL|0666);
if(shmid==-1) printf("get error:%m\n"),exit(-1);
//2.挂载共享内存shmat
p=shmat(shmid,0,0);
if(p==(int*)-1) printf("at error:%m\n"),exit(-1);
//3.访问共享内存
while(1)
{
*p=i;
sleep(1);
i++;
}
}
进程B
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/shm.h>
#include <sys/ipc.h>
key_t key;
int shmid;
int *p;
void deal(int s)
{
if(s==2)
{
//4.卸载共享内存shmdt
shmdt(p);
exit(0);
}
}
main()
{
signal(SIGINT,deal);
//1.创建共享内存shmget
key=ftok(".",255);
if(key==-1) printf("ftok error:%m\n"),exit(-1);
shmid=shmget(key,4,0);
if(shmid==-1) printf("get error:%m\n"),exit(-1);
//2.挂载共享内存shmat
p=shmat(shmid,0,0);
if(p==(int*)-1) printf("at error:%m\n"),exit(-1);
//3.访问共享内存
while(1)
{
sleep(1);
printf("%d\n",*p);
}
}原文:http://blog.csdn.net/aspnet_lyc/article/details/20915639