1.创建共享内存对象函数
1)函数原型
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
返回值: 如果成功,返回共享内存段标识符。如果失败,则返回-1。
key:用户指定的共享内存键值,一般可以设置为IPC_PRIVATE(0)
size:共享内存大小
shmflg: IPC_CREAT, IPC_EXCL等权限组合
2)errno
EINVAL (无效的内存段大小)
EEXIST (内存段已经存在,无法创建)
EIDRM (内存段已经被删除)
ENOENT (内存段不存在)
EACCES (权限不够)
ENOMEM (没有足够的内存来创建内存段)
2、共享内存对象的控制操作
1)函数原型#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
返回: 成功返回0、出错返回-1
2)参数shmid:共享内存ID
buf:共享内存属性指针
cmd参数取值:
IPC_STAT 获取共享内存段属性
IPC_SET 设置共享内存段属性
IPC_RMID 删除共享内存段
SHM_LOCk 锁定共享内存段页面(页面映射到物理内存不和外存进行换入换出操作)
SHM_ULOCK 解除共享内存段页面的锁定
3.共享内存映射1) 函数原型
#include <sys/shm.h>
void* shmat(int shmid, char *shmaddr, int shmflg);
返回: 成功返回共享内存段连接到进程中的地址,失败返回-12) 参数
shmid:共享内存ID
shmaddr:映射到进程虚拟内存空间的地址,建议设置为0,由操作系统分配。
shmflag:若shmaddr设置为0,则shmflag也设置为0.
SHM_RND
SHMLBA 地址为2的乘方
SHM_RDONLY 只读方式链接
3)errno
EINVAL (无效的IPC ID 值或者无效的地址)
ENOMEM (没有足够的内存)
EACCES (存取权限不够)
4.解除映射int shmdt(char* shmaddr);
返回:如果失败,则返回-1参数:
shmaddr:为shmat返回的地址
示例代码:
父进程创建一个子进程,然后父进程向共享内存中写入数据,子进程读取共享内存中的数据。为了保证父进程首先写入数据,其后子进程进行读取这种互斥机制,引入了管道机制,子进程通过等待管道中的数据,将自己阻塞,父进程向共享内存中写入数据后,向管道写入一个字节,触发子进程阻塞结束,从而子进程去读共享内存中数据。
tell.h
#ifndef __TELL_H__
#define __TELL_H__
extern void init();
extern void wait_pipe();
extern void notify_pipe();
extern void destroy_pipe();
#endif
tell.c
#include <stio.h>
#include <stdlib.h>
#include <string.h>
#include "tell.h"
static int fd[2];
void init()
{
if(pipe(fd) < 0)
{
perror("pipe error");
}
}
void wait_pipe()
{
char c;
if(read(fd[0], &c, 1) < 0)
{
perror("wait pipe error");
}
}
void notify_pipe()
{
char c = 'c';
if(write(fd[1], &c, 1) !+ 1)
{
perror("notify pipe error");
}
}
void destroy_pipe()
{
close(fd[0]);
close(fd[1]);
}
cal_shm.c
#include <sys/shm.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "tell.h"
int main()
{
int shmid;
if((shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT|IPC_EXCL|0777)) < 0)
{
perror("shmget error");
exit(1);
}
pid_t pid;
init();//初始化管道
if((pid = fork()) < 0)
{
perror("fork error");
exit(0);
}
else if(pid > 0)
{
//进行共享内存映射
int *pi = (int *)shmat(shmid, 0, 0);
if(pi == (int*)(-1))
{
perror("shmat error");
exit(1);
}
//往共享内存中写入数据(通过操作映射的地址即可)
*pi = 100;
*(pi + 1) = 200;
//操作完毕解除共享内存的映射
shmdt(pi);
//通知子进程读取数据
notify_pipe();
destory_pipe();
wait(0);
}
else
{//子进程
wait_pipe();
//子进程去从共享内存中读取数据
//子进程进行共享内存的映射
int *pi = (int*)shmat(shmid, 0, 0);
if(pi == (int*)(-1))
{
perror("shmat error");
exit(1);
}
print("start: %d, end: %d\n", *pi, *(pi +1));
//读取完毕后解除映射
shmdt(pi);
//删除共享内存
shmctl(shmid, IPC_RMID, NULL);
destory_pipe();
}
return 0;
}