前言
本文为笔者学习笔记,若有不妥之处,欢迎斧正。
一、共享内存概述
简单来说共享内存的概念:是指两个或多个进程共享已给定的存储区。
共享内存的特点:
- 共享内存是最快的一种IPC,进程是直接对内存进行存取。
- 支持多个进程同时操作,所以需要同步操作。(也就是配合信号量使用)
- 信号量+共享内存通常结合起来一起使用,信号量用来同步对共享内存的访问。
共享内存的实现机制:共享内存时通过把一块内存分别映射到不同的进程空间中实现进程间通信。而共享内存本身不带任何互斥与同步机制,但当多个进程同时对同一个内存进行读写操作时会破坏该内存的内容。所以,在实际中,同步与互斥机制需要用户来完成。
共享内存通信的过程:
- 当用shmget函数创建一段共享内存时,必须指定其 size;而如果引用一个已存在的共享内存,则将 size 指定为0 。
- 当一段共享内存被创建以后,它并不能被任何进程访问。必须使用shmat函数连接该共享内存到当前进程的地址空间,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问。
- shmdt函数是用来断开shmat建立的连接的。注意,这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已。
- shmctl函数可以对共享内存执行多种操作,根据参数 cmd 执行相应的操作。常用的是IPC_RMID(从系统中删除该共享内存)。
二、共享内存相关API详解
1.获取键值
函数原型:
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
函数作用:生成消息队列的键值(每一个消息队列都有一个对应的键值相关联,共享内存和信号量也需要)。
参数说明:
- pathname:路径名。
- proj_id:是0到25之间的值,可以随意取。
返回值:成功返回键值,失败返回-1。
2.创建或者获取一段共享内存
函数原型:
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
函数作用:创建或者获取一段贡献内存空间。
参数说明:
- key:ftok的返回值,键值。
- size:共享内存的大小
- shmflg:常用 IPC_CREAT|0666。其他可使用man手册进行查询。
返回值:成功返回共享内存ID,失败返回-1。
3.连接共享内存
函数原型:
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
函数作用:连接到创建或获取到的共享内存的地址空间。
参数说明:
- shmid:共享内存ID。
- shmaddr:挂载到哪一块虚拟地址空间,填NULL,默认让操作系统选择一块空白的虚拟地址。
- shmflg:参数为0。
返回值:成功返回共享内存的指针(也就是返回可用的地址),失败返回NULL。
4.断开连接共享内存
函数原型:
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
函数作用:断开进程与共享内存的连接。
参数说明:
- shmaddr:是shmat函数返回的地址
返回值:成功返回0,失败返回-1。
5.控制共享内存
函数原型:
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
函数作用:控制共享内存的相关信息(通常用来销毁共享内存)
参数说明:
- shmid:共享内存的ID。
- cmd:常用 IPC_RMID。
- buf:常使用NULL。
返回值:成功返回0,失败返回-1;
三、代码演示
- shmWrite程序
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main(void)
{
key_t key;
int shmid;
char *write=NULL;
key =ftok(".",'z');
if(key == -1)
{
perror("ftok failed:");
exit(-1);
}
shmid = shmget(key,1024*4,IPC_CREAT|0666);
if(shmid == -1)
{
perror("shmget failed:");
exit(-1);
}
write = shmat(shmid,NULL,0);
if(write == NULL)
{
perror("shmat failed:");
exit(-1);
}
strcpy(write,"Good night!");
printf("send ok\n");
sleep(10);
int err = shmdt(write);
if(err == -1)
{
perror("shmdt failed:");
exit(-1);
}
err = shmctl(shmid,IPC_RMID,NULL);
if(err == -1)
{
perror("shmctl failed:");
exit(-1);
}
return 0;
}
- shmRead程序
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main(void)
{
key_t key;
int shmid;
int err;
char *write = NULL;
key = ftok(".",'z');
if(key == -1)
{
perror("ftok failed:");
exit(-1);
}
shmid = shmget(key,1024*4,0);
if(shmid == -1)
{
perror("shemget failed:");
exit(-1);
}
write = shmat(shmid,NULL,0);
if(write == NULL)
{
perror("shmat failed:");
exit(-1);
}
printf("receive data:%s\r\n",write);
err = shmdt(write);
if(err == -1)
{
perror("shmdt failed:");
exit(-1);
}
/*
*err = shmctl(shmid,IPC_RMID,NULL);
*if(err == -1)
*{
* perror("shmctl failed:");
* exit(-1);
*}
*
* */
return 0;
}
程序运行的结果如下:
//shmWrite
send ok
//shmRead
receive data:Good night!