1、共享内存介绍:
共享内存是一种最为高效的进程间通信方式,进 程可以直接读写内存,而不需要任何数据的拷贝。
为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间。
进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高的效率。
由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等。
2、共享内存的特点:
2.1 共享内存是进程间共享数据的一种最快的方法。一个进程向共享的内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。
2.2 使用共享内存要注意的是多个进程之间对一个给定存储区访问的互斥。若一个进程正在向共享内存区写数据,则在它做完这一步操作前,别的进程不应当去读、写这些数据。
3、框架图:
4、共享内存API解析:
4.1创建或获取共享内存:
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
功能:
创建或获取共享内存
参数:
1> key:密钥 一组16进制的地址
1>自动获取:IPC_PRIVATE:系统自动创建分配共享内存
弊端:永远都找不到同一块内存,不断创建新的共享内存,不采用
2>手动获取:
采用ftok函数
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
功能:
手动创建或获取key
参数:
1>pathname:工程文件名(带路径)
2>proj_id :工程代号
返回值:
成功返回key
失败返回-1,并设置错误码
//只要参数不变化,总可以找到同一key
2>size:共享内存大小
3>shmflg:使用权限:
IPC_CREAT|0666
返回值:
成功返回shmid
失败返回-1,并设置错误码
ftok:函数:创建一个内核中唯一的共享内存标识符,使得内核可以识别唯一的共享内存或者信号量或者消息队列。
4.2贡献内存映射:
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:
将共享内存映射到用户空间(进程)
参数:
1>shmid:共享内存ID
2>shmaddr:你想要映射到的地方:NULL 自行寻找
3>shmflg:0 可读可写
返回值:
成功返回映射到的地址
失败返回(void *)-1,并设置错误码
4.3 解除映射
shmdt
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmaddr);
功能:
解除映射操作
参数:
shmaddr:需要解除的地址
返回值:
成功返回0
失败返回-1,并设置错误码
4.4删除共享内存
4>删除共享内存
shmctl --->共享内存操作
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:
对共享内存进行操作
PS:删除只是其中一环
参数:
1>shmid:需要操作的共享内存ID号
2>cmd:删除共享内存操作:
IPC_RMID:删除共享内存
3>buf:结构体指针:用来赋值的操作
IPC_RMID:NULL
返回值:
IPC_RMID:成功返回0
失败返回-1,并设置错误码
5、查看系统中的共享内存
ipcs -m
6、删除系统中的共享内存
ipcrm -m 共享内存ID
7、共享内存示例:
一端写入:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main(){
//创建密钥
key_t key=ftok("pause.c",1);
if(key<0){
perror("ftok");
return -1;
}
printf("key:%#x\n",key);
//1>创建或获取共享内存
int shmid=shmget(key,200,IPC_CREAT|0666);
//int shmid=shmget(IPC_PRIVATE,200,IPC_CREAT|0666);
if(shmid<0){
perror("shmget");
return -1;
}
printf("共享内存ID号为:%d\n",shmid);
//2>将共享内存映射到用户空间
void *addr=shmat(shmid,NULL,0);
if(addr==(void *)-1){
perror("shmat");
return -1;
}
char *p=(char *)addr;//将万能指针型转化为char *
printf("进程的地址为:%p\n",p);
//3>解除映射
int ret=shmdt(addr);
if(ret<0){
perror("shmdt");
return -1;
}
//4>删除共享内存
ret=shmctl(shmid,IPC_RMID,NULL);
if(ret<0){
perror("shmctl");
return -1;
}
//通信?
//while(1){
scanf("%s",p);//此时,p为野指针,发生段错误
//}
return 0;
}
一端读取:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main(){
//创建密钥
key_t key=ftok("pause.c",1);
if(key<0){
perror("ftok");
return -1;
}
printf("key:%#x\n",key);
//1>创建或获取共享内存
int shmid=shmget(key,200,IPC_CREAT|0666);
//int shmid=shmget(IPC_PRIVATE,200,IPC_CREAT|0666);//最好不使用
if(shmid<0){
perror("shmget");
return -1;
}
printf("共享内存ID号为:%d\n",shmid);
//2>将共享内存映射到用户空间
void *addr=shmat(shmid,NULL,0);
if(addr==(void *)-1){
perror("shmat");
return -1;
}
char *p=(char *)addr;//将万能指针型转化为char *
printf("进程的地址为:%p\n",p);
//3>通信?
while(1){//共享内存是不会阻塞的
printf("%s\n",p);
}
return 0;
总结:
共享内存:利用内存区,映射到两个进程的空间,两个进程通过内存进行数据传递,直接输入到内存区,和直接输出,效率最高 因为操作内存区,操作如果不严谨,遇到的段错误可能相对较多。 内存区是直接输入输出的,所以并没有阻塞概念
while(1)//不可用,需要另外的手段。