共享内存就是允许两个或多个进程共享一片存储区,是操作系统在实际物理内存开辟一块空间,当一个进程往该空间写入内容时,另外一进程会访问该空间,得到写入的值,即实现了进程间的通信。
共享内存做到数据不需要在客户机和服务器端之间来回复制,数据直接写到内存中,不需要多次数据拷贝,是进程间最有效的方式
功能 : 获取一个独一无二的key,作为传给共享内存的一个参数
#include
#include
key_t ftok(const char *pathname, int proj_id);
key_t key = ftok("./read", 'a');
pathname:
提前创建的可访问文件的文件名,可以随意写
proj_id:
任意一个字符
返回值:
成功则返回生成的key值,失败则返回-1
功能:创建/打开一个共享内存对象
#include
#include
//在内核上创建共享内存
int shemid = shmget(key, 1024, IPC_CREAT | 0666);
int shmget(key_t key, size_t size, int shmflg);
key:
表示要打开或者创建一个对象的“密钥”
可以写0或者IPC_PRIVATE:表示共享内存对象是私有的
size:
要创建的共享内存大小
shmflg:
打开或者创建时的权限
IPC_CREAT:不存在则创建
IPC_EXCL:存在(如果加上了IPC_CREAT)就报错
0666
返回值:
成功返回ID号,失败返回-1
功能:把内核中的共享内存空间映射到用户空间
#include
#include
void *shmat(int shmid, const void *shmaddr, int shmflg);
char *shmaddr = shmat(shmid, NULL, 0);
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid:
共享内存的id号
shmaddr:
可以指定要映射的空间地址
NULL:表示系统决定
0x...:表示指定要把内核空间映射到这个地址
shmflg:
表示共享内存的操作权限(读写)
SHM_RDONLY:表示只读(不用)
0:可读可写
返回值:
成功返回映射后的用户空间地址,失败返回(void *)-1
功能:把shmat映射后的空间取消掉,释放进程地址空间
#include
#include
int shmdt(const void *shmaddr);
shmaddr:
shmat返回的地址(映射地址)
返回值:
成功返回0,失败返回-1
功能:整体控制共享内存对象
#include
#include
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmctl(shmid, IPC_RMID, NULL);
shmid:
共享内存对象ID号
cmd:
要执行的操作
IPC_STAT (获取对象属性)
IPC_SET (设置对象属性)
IPC_RMID (删除对象)
buf:
用于设置或者获取对象的属性,如果是删除对象,写NULL
返回值:
成功返回0,失败返回-1
注:删除对象并不是直接删除,而是标记这个对象为删除状态
write.c依次往共享内存中输入字符a-z, read.c读取共享内存中的数据,并打印出来
write.c
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
key_t key = ftok("./read", 'a');
if(key < 0)
{
perror("ftok");
return -1;
}
// 创建共享内存
int shmid = shmget(key, 1024*4, IPC_CREAT | 0666);
if(shmid < 0)
{
perror("shmget");
return -1;
}
// 映射空间地址
char *shmaddr = shmat(shmid, NULL, 0);
if(shmaddr == (void *)-1)
{
perror("shmat");
return -1;
}
char c='a';
for( ; c <= 'z'; c++)
{
printf("%c\n",c);
shmaddr[c-'a']=c;
sleep(1);
}
shmdt(shmaddr);
shmctl(shmid, IPC_RMID, NULL);
}
read.c
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
key_t key = ftok("./read", 'a');
if(key < 0)
{
perror("ftok");
return -1;
}
//在内核上创建共享内存
int shmid = shmget(key, 1024*4,IPC_CREAT|0666);
if(shmid < 0)
{
perror("shmget");
return -1;
}
//映射空间地址
char *shmaddr = shmat(shmid, NULL, 0);
if(shmaddr == (void *)-1)
{
perror("shmat");
return -1;
}
int i = 20;
while(i)
{
printf("result : %s\n", shmaddr);
sleep(1);
i--;
}
shmdt(shmaddr);
shmctl(shmid, IPC_RMID, NULL);
}
注意 : 当运行程序时,先运行read.c,程序启动就直接读取共享内存中的数据,此时并没有往共享内存中写入数据,
但是read.c并没有阻塞
ipcs -m //查看当前系统的共享内存
ipcs -m shmid //删除某个共享内存
当我结束两个进程时,如果代码中没有shmctl,那么共享内存还会一直存在,会造成内存泄漏,所以当我们使用shmget创建共享内存后,如果不在使用该共享内存,应当即时释放