共享内存机制是允许两个或多个进程(不相关或有亲缘关系)访问同一逻辑内存的机制。它是共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。
原理:
利用共享内存完成进程间通信,两个进程都可以通过虚拟地址空间到用户页表,然后通过用户级页表映射到物理内存的相同一块内存区域。
ftok
shmget
shmat
shmdt
shmctl
shmwrite.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
struct Conn_stat{
int count;
char ip[64];
};
int main(void){
void *shm = NULL;
int shmid = 0;//存储共享内存的标识
struct Conn_stat stat = {0,"127.0.0.1"};
//创建共享内存
shmid = shmget((key_t)1234,sizeof(struct Conn_stat),0666 | IPC_CREAT);
if(shmid == -1){
fprintf(stderr, "shmget failed\n");
exit(1);
}
//将共享内存挂接到当前进程的地址空间
shm = shmat(shmid,(void*)0,0);
if(shm == (void*)-1){
fprintf(stderr, "shmat failed\n");
exit(2);
}
printf("Memory attached at %p\n", shm);
//设置共享内存
struct Conn_stat *p = (struct Conn_stat*)shm;
memcpy(p,&stat,sizeof(struct Conn_stat));
//修改共享内存中的数据
int i = 0;
while((i++) < 50){
p->count++;
sleep(1);
}
//把共享内存从当前进程中分离
if(shmdt(shm) == -1){
fprintf(stderr, "shmdt failed\n");
exit(3);
}
return 0;
}
shmread.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
#include <string.h>
#include <errno.h>
struct Conn_stat{
int count;
char ip[64];
};
int main(void){
void *shm = NULL;//分配的共享内存的原始首地址
struct Conn_stat *stat = NULL;
int shmid;//共享内存标识符
//创建共享内存
shmid = shmget((key_t)1234, sizeof(struct Conn_stat), 0666|IPC_CREAT);
if(shmid == -1){
fprintf(stderr, "shmget failed\n");
exit(0);
}
//将共享内存挂接到当前当前进程的地址空间
shm = shmat(shmid, 0, 0);
if(shm == (void*)-1){
fprintf(stderr, "shmat failed\n");
exit(1);
}
printf("\nMemory attached at %p\n", shm);
//设置共享内存
stat = (struct Conn_stat*)shm;
int i = 0;
while((i++) < 10){
printf("ip = %s ,count: %d\t\t\n", stat->ip, stat->count);
sleep(1);
}
//把共享内存从当前进程中分离
if(shmdt(shm) == -1){
fprintf(stderr, "shmdt failed\n");
exit(2);
}
//删除共享内存
if(shmctl(shmid, IPC_RMID, 0) == -1){
fprintf(stderr, "shmctl(IPC_RMID) failed, reason: %s\n",strerror(errno));
exit(3);
}
return 0;
}
原理:
将一个普通文件或者其它对象映射进内存。
mmap
munmap
map_write.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<string.h>
struct Conn_stat{
int count;
char ip[64];
};
//这个进程创建映射区进行写
int main(int argc,char* argv[]){
if(argc != 2){
printf("Usage: %s file.\n",argv[0]);
exit(1);
}
struct Conn_stat stat = {0,"127.0.0.1"};
//打开文件
int fd = open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0644);
if(fd<0){
perror("open");
exit(2);
}
//将文件截断为第二个参数这么大
ftruncate(fd,sizeof(struct Conn_stat));
//创建一个结构体大小的共享映射区。共享映射区我们可以当做数组区看待。
struct Conn_stat *p = (struct Conn_stat*)mmap(NULL,sizeof(struct Conn_stat),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
if(p == MAP_FAILED){
perror("mmap");
exit(3);
}
close(fd);//关闭不用的文件描述符
memcpy(p,&stat,sizeof(struct Conn_stat));
while(p->count < 30){
p->count++;
sleep(1);
}
//解除映射
int ret = munmap(p,sizeof(struct Conn_stat));
if(ret < 0){
perror("mmumap");
exit(4);
}
return 0;
}
map_read.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h>
struct Conn_stat{
int count;
char ip[64];
};
int main(int argc,char *argv[]){
if(argc != 2){
printf("Usage: %s file.\n",argv[0]);
exit(1);
}
//打开文件-只读,注意与写中的参数不同
int fd = open(argv[1],O_RDONLY,0644);
if(fd < 0){
perror("open");
exit(2);
}
struct Conn_stat stat;
//注意与写中的参数不同
struct Conn_stat *p = (struct Conn_stat*)mmap(NULL,sizeof(struct Conn_stat),PROT_READ,MAP_SHARED,fd,0);
if(p == MAP_FAILED){
perror("mmap");
exit(3);
}
close(fd);
int i = 0;
while((i++) < 10){
printf("ip = %s ,count: %d\t\t\n",p->ip,p->count);
sleep(1);
}
//接触映射
int ret = munmap(p,sizeof(stat));
if(ret < 0){
perror("mmumap");
exit(4);
}
return 0;
}