共享内存
特点:最快最简单的IPC
共享内存不用像管道和消息队列进行内核空间向用户空间的转变,它是将一块物理内存通过shmat函数映射到进程的虚拟内存上,进程可以直接操作内存
/*shm_write.c*/
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
// int shmget(key_t key, size_t size, int shmflg);
// void *shmat(int shmid, const void *shmaddr, int shmflg);
// shmid:共享内存id;shaddr:若为NULL则系统自动分配合适空间; shmflg:默认为'0'可读可写
// int shmdt(const void *shmaddr);
// int shmctl(int shmid, int cmd, struct shmid_ds *buf);
int main()
{
key_t key;
int shmid;
char *shmaddr;
//获取key值
key = ftok(".",1);
if(key == -1){
printf("ftok error\n");
perror("why:");
}
//开辟共享内存
shmid = shmget(key,1024*4,IPC_CREAT|0666);
if(shmid == -1){
perror("shmget:");
exit(-1);
}
//内存映射
shmaddr = shmat(shmid,0,0);//shmid,共享内存id;'0':从第一块共享内存映射;'0':可读可写(默认)
strcpy(shmaddr,"hello world");
//解除映射,解除映射后信息存在物理内存之中
shmdt(shmaddr);
return 0;
}
/*shm_read.c*/
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
int main()
{
key_t key;
int shmid;
char *shmaddr;
key = ftok(".",1);
if(key == -1){
perror("why:");
}
shmid = shmget(key,1024*4,0);
if(shmid == -1){
printf("creat shared memory failed\n");
perror("shm:");
exit(-1);
}
shmaddr = shmat(shmid,0,0);
printf("%s\n",shmaddr);
shmdt(shmaddr);
//删除共享内存,释放物理内存
shmctl(shmid,IPC_RMID,0);
return 0;
}
ps:
1.同一个进程多次进行shmat会出现什么问题?
当首次创建共享内存段时,它不能被任何进程所访问,为了使共享内存区可以被访问,则必须通过shmat函数将其映射到自己的进程空间中。这样进程就与共享内存建立了连接。
这样挂载一个共享内存如果是第一次调用时没有问题的,但是一个进程是可以对同一个共享内存多次shmat进行挂载的,物理内存是指向同一块,如果shmaddr为NULL,则每次返回的线性地址空间都不同,而且指向这块共享内存的引用计数会增加,也就是进程多块线性空间会指向同一块物理地址,这样会一直消耗进程的虚拟内存空间,很有可能会最后导致进程线性空间被使用完,而导致下次shmat或者其他操作失败。
2.查看系统可共享内存大小的指令:
cat /proc/sys/kernel/shmmax <OS分配>
cat /proc/sys/kernel/shmmni <应该是4096>
3.共享内存没有同步机制,一般需要借助其他手段进行同步工作常用的就是信号了,一般是做互斥,因为操作同一片内存,不同进程若同时读写则会造成数据的破坏,这时就需要借助信号限制不同进程的操作