共享内存数据结构
struct shmid_ds {
struct ipc_perm shm_perm; //IPC对象数据结构
size_t shm_segsz; //共享内存段的大小
time_t shm_atime; //最后一次映射共享内存的时间
time_t shm_dtime; //最后一次解除映射的时间
time_t shm_ctime; //最后一次共享状态发生改变的时间
pid_t shm_cpid; //共享内存创建者的进程号
pid_t shm_lpid; //最后一次连接或脱离共享内存的进程号码
shmatt_t shm_nattch; //当前共享内存被连接的次数
...
};
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmget函数
功能:用来创建共享内存
int shmget(key_t key,size_t size,int shmflg);
参数
key:这个共享内存段名字
size:共享内存大小
shmflg:用法类似msgget中的msgflg参数;
返回值:
成功返回一个非负整数,即该共享内存段的标识码,失败返回-1
shmat函数
功能:将共享内存段连接到进程地址空间
void *shmat(int shmid,const *shmaddr,int shmflg);
连接到本进程地址空间, 成功连接之后, 而且如果这块内存中有数据, 则就可以直接将其中的数据取出来
参数:
shmaddr:指定连接的地址(推荐使用NULL)
shmflg:一般指定为0, 表示可读,可写; 而它的另外两个可能取值是SHM_RND和SHM_RDONLY(见下)
返回值:
成功返回一个指针,指向共享内存起始地址;失败返回(void *) -1
shmaddr与shmflg组合说明 | |
shmaddr为NULL | Linux内核自动为进程连接到进程的内存(推荐使用) |
shmaddr不为NULL且shmflg无SHM_RND标记 | 以shmaddr为连接地址 |
shmaddr不为NULL且shmflg设置了SHM_RND标记 | 连接的地址会自动向下调整为SHMLBA的整数倍; 公式:shmaddr - (shmaddr % SHMLBA) SHMLBA为内存页面的大小(4K) |
shmflg=SHM_RDONLY | 表示连接只能用来读共享内存, |
shmdt函数
功能:将共享内存段与当前进程脱离
int shmdt(const void *shmaddr);
参数
shmaddr:由shmat所返回的值
返回值:
成功返回0,失败返回-1
注意:将共享内存与当前进程脱离不等于删除共享内存段
shmctl函数
功能:共享内存的控制函数
int shmctl(int shmid,int cmd,struct shmid_ds *buf);
参数
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作(有三个可取值)
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构(也就是动作命令带的参数)
返回值:
成功返回0,失败返回-1.
//共享内存写
#include <unistd.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while(0)
typedef struct stu
{
char name[32];
int age;
}STU;
int main(int argc,char *argv[])
{
//创建一个共享内存
int shmid;
//第二个参数是创建的共享内存的大小
shmid=shmget(1234,sizeof(STU),IPC_CREAT | 0666);
if(shmid==-1)
ERR_EXIT("shmget");
STU *p;
//将这块内存连接到进程的地址空间中
//0表示连接的这块内存既可读又可写
p=shmat(shmid,NULL,0);
if(p==(void*)-1)
ERR_EXIT("shmat");
strcpy(p->name,"wangkai");
p->age=20;
//判断数据是否被读走,若没有,则一直等待,不断开进程与共享内存区的连接
while(1)
{
if(memcmp(p,"quit",4)==0)
break;
}
//断开进程与共享内存区的连接
shmdt(p);
//从系统中删除由shmid标识的共享内存区并拆除它
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
#include <unistd.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
}while(0)
typedef struct stu
{
char name[32];
int age;
}STU;
int main(int argc,char *argv[])
{
//创建一个共享内存
int shmid;
shmid=shmget(1234,0,0);
if(shmid==-1)
ERR_EXIT("shmget");
STU *p;
//将这块内存连接到进程的地址空间中
//0表示连接的这块内存既可读又可写
p=shmat(shmid,NULL,0);
if(p==(void*)-1)
ERR_EXIT("shmat");
printf("name=%s age=%d\n",p->name,p->age);
//读走以后将前4个字节置为quit,已提示发送方已收到,可以断开连接
memcpy(p,"quit",4);
shmdt(p);
return 0;
}
System V共享内存小结:
1.共享内存被别的程序占用,则删除该共享内存时,不会马上删除(引用计数计数);
2.此时会出现一个现象:该共享内存的key变为0x00000000,变为私有;
3.此时还可以读,但必须还有办法获取该共享内存的ID(shmid),因为此时试图通过该共享内存的key获取该共享内存,是白费的