共享内存:
目的: 用于进程间的数据共享
原理: 开辟一块物理内存空间,各个进程将同一块物理内存空间映射到自己的虚拟地址空间中,通过虚拟地址进行访问,进而实现数据共享
共享内存是最快的进程间通信方式,因为通过虚拟地址空间映射后,直接通过虚拟地址访问物理内存,相较于其他方式少了两部数据拷贝操作。
操作流程:
1.创建或打开共享内存
int shmget(key_t key, size_t size, int shmflg);
key:标识符—通过相同的标识符,多个进程可以打开同一块共享内存;
size:要创建的共享内存大小
shmflg:打开方式+权限;IPC_CREAT|IPC_EXCL|0664
返回值:成功返回非负整数-操作句柄;失败返回-1
2.与进程建立映射关系
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmid:shmget返回的操作句柄
shmaddr:映射首地址,通常置NULL
shmflg:SHM_RDONLY-----只读; 0—可读可写
返回值:成功返回映射值后的首地址;失败返回(*void)-1
3.对共享内存进行内存操作:
memcpy,strcpy,printf…
4.与进程间解除映射关系
int shmdt(void *shmaddr)
shmaddr:shmat返回的映射首地址
返回值:成功返回0,失败返回-1;
5.删除共享内存
int shmctl(int shmid,int cmd,struct shmid_ds *buf)
shmid:shmget返回的操作句柄
cmd:要对共享内存进行的操作类型
IPC_RMID:标记要删除的共享内存
映射连接数为0时删除共享内存;禁止新的映射连接
buf:用于获取或设置共享内存属性的,简单使用置NULL即可
返回值:成功返回0;失败返回-1
代码:
//shm_read.c
#include<stdio.h> //printf
#include<unistd.h>
#include<sys/shm.h>
#include<stdlib.h>
#define IPC_KEY 0x01234567
int main(int argc,char *argv[]) //运行参数个数 运行参数字符串首地址
{
//1.创建或打开共享内存
//int shmget(标识,共享内存大小,权限+打开方式)
int shmid=shmget(IPC_KEY,32,IPC_CREAT|0664);
if(shmid<0){
perror("shmget error");
return -1;
}
//2.与进程间建立映射关系
//void *shmat(操作句柄,映射首地址,访问方式)
void *shm_start=shmat(shmid,NULL,0); //0---可读可写 SHM_RDONLY----只读
if(shm_start==(void*)-1){
perror("shmat error");
return -1;
}
//3.对共享内存进行内存操作
while(1){
printf("%s\n",(char*)shm_start);
sleep(1);
}
//4.与进程间解除映射关系
//int shmdt(void *shmaddr)
shmdt(shm_start);
//5.删除共享内存
//int shmctl(操作句柄,操作类型,信息结构)
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
//shm_write.c
#include<stdio.h>
#include<unistd.h>
#include<sys/shm.h>
#include<stdlib.h>
#define IPC_KEY 0x01234567
int main(int argc,char *argv[]) //运行参数个数 运行参数首地址
{
//1.建立或开辟共享内存
//int shmget(内存标记,内存大小,打开方式+权限)
int shmid=shmget(IPC_KEY,32,IPC_CREAT|0664);
if(shmid<0){
perror("shmget error");
return -1;
}
//2.与进程建立映射关系
//void* shmat(标志,映射首地址,访问方式)
void *shm_start=shmat(shmid,NULL,0);
if(shm_start==(void*)-1){
perror("shmat error");
return -1;
}
//3.对共享内存进行内存操作
int i=0;
while(1){
scanf(shm_start,"今天你开心吗?+%d",i++);
sleep(1);
}
//4.解除映射关系
//int shmdt(void *shmaddr)
shmdt(shm_start);
//5.删除共享内存
shmctl(shmid,IPC_RMID,NULL);
return 0;
}