一.共享内存数据结构
对于每个共享内存区,内核维护如下信息结构,定义在<sys/shm.h>, 在ubuntu中路径:/usr/include/linux/shm.h
二. System V共享内存函数:
#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);
(1)
功能:用来创建共享内存
原型 int shmget(key_t key, size_t size, int shmflg);
参数:
key: 这个共享内存段名字
size: 共享内存大小
shmflg: 由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值: 成功返回一个非负整数,即该共享内存段的标识码;
失败返回-1
(2)
功能:将共享内存段连接到进程地址空间
原型
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
shmid: 共享内存标识
shmaddr: 指定连接的地址
shmflg: 它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个字节;失败返回-1
shmaddr 为NULL,内核自动选择一个地址
shmaddr 不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。
公式:shmaddr - (shmaddr % SHMLBA) # SHMLBA为4096
shmflg=SHM_RDONLY,表示连接操作用来只读共享内存
(3)
功能:将共享内存段与当前进程脱离
原型 int shmdt(const void *shmaddr);
参数
shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段
(4)
功能:用于控制共享内存
原型 int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数
shmid: 由shmget返回的共享内存标识码
cmd: 将要采取的动作(有三个可取值)
buf: 指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1
cmd 的取值如下,与消息队列类似:
IPC_STAT 把shmid_ds结构中的数据设置为共享内存的当前关联值
IPC_SET 在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds数据结构中给出的值
IPC_RMID 删除共享内存段
shmwrite.c
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<sys/ipc.h>
#include<sys/shm.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 err");
STU *p;
p = shmat(shmid,NULL,0);//将共享内存段连接到进程地址空间
if(p == (void*)-1) //error (void *) -1 is returned
ERR_EXIT("shmat err");
strcpy(p->name,"list");
p->age = 20;
while(1) // 等待,接收内存中有quit字符串时,代表读取完成
{
if(memcmp(p,"quit",4) == 0)// 需要注意的是,这里比较的是内存
break;
}
//sleep(10);
shmdt(p);//将共享内存段与当前进程脱离
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
shmread.c
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/ipc.h>
#include<sys/msg.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<sys/ipc.h>
#include<sys/shm.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 err");
STU *p;
p = shmat(shmid,NULL,0);//将共享内存段连接到进程地址空间
if(p == (void*)-1) //error (void *) -1 is returned
ERR_EXIT("shmat err");
printf("name=%s age=%d\n",p->name,p->age);
memcpy(p,"quit",4); // 读取完数据后,向内存中写入4个字节的数据,代表读取完成
shmdt(p);//将共享内存段与当前进程脱离
return 0;
}