共享内存是被多个进程共享的一部分物理内存。共享内存是进程间共享数据的一种最快的方式,一个进程向共享内存区域写入数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。
共享内存实现分两个步骤:
创建共享内存,使用shmget函数
映射共享内存,使用shmat函数
共享内存是一种最为高效的进程间通信方式。因为进程可以直接读写内存,不需要任何数据的拷贝。为了在多个进程间交换信息,内核专门留出了一块内存区。这段内存区可以由需要访问的进程将其映射到自己的私有地址空间。因此,进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高了效率。当然,由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等 。
/*shmem.c*/
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define BUFFER_SIZE 2048
int main()
{
pid_t pid;
int shmid;
char *shm_addr;
char flag[]="WROTE";
char *buff;
/*创建共享内存*/
if((shmid=shmget(IPC_PRIVATE,BUFFER_SIZE,0666))<0)
{
perror("shmget");
exit(1);
}
else
printf("Create shared-memory:%d\n",shmid);
/*显示共享内存情况*/
system("ipcs -m");
pid=fork();
if(pid==-1)
{
perror("fork");
exit(1);
}
else if(pid==0)/*子进程*/
{
/*映射共享内存*/
if((shm_addr=shmat(shmid,0,0))==(void *)-1)
{
perror("child:shmat");
exit(1);
}
else
printf("child:atttach shared-memory:%p\n",shm_addr);
system("ipcs -m");
/*通过检查在共享内存的头部是否标志字符串"WORTE"来确认*/
/*父进程已经向内存写入有效数据*/
while(strncmp(shm_addr,flag,strlen(flag)))
{
printf("child:wait for enable data:...\n");
sleep(5);
}
/*获取共享内存有效数据并显示*/
strcpy(buff,shm_addr+strlen(flag));
printf("child:shared-mempory:%s\n",buff);
/*解除共享内存映射*/
if((shmdt(shm_addr))<0)
{
perror("shmdt");
exit(1);
}
else
printf("child:deattach shared-memory\n");
system("ipcs -m");
/*删除共享内存*/
if(shmctl(shmid,IPC_RMID,NULL)==-1)
{
perror("child:shmctl(IPC_RMID)\n");
exit(1);
}
else
printf("delete shared-memory\n");
system("ipcs -m");
}
else
{
/*映射共享内存*/
if((shm_addr=shmat(shmid,0,0))==(void *)-1)
{
perror("parent:shmat");
exit(1);
}
else
printf("parent:atttach shared-memory:%p\n",shm_addr);
sleep(1);
printf("\ninput some string:\n");
fgets(buff,BUFFER_SIZE,stdin);//fgets是阻塞型字符串输入
strncpy(shm_addr+strlen(flag),buff,strlen(buff));
strncpy(shm_addr,flag,strlen(flag));
/*解除共享内存*/
if((shmdt(shm_addr))<0)
{
perror("shmdt");
exit(1);
}
else
printf("child:deattach shared-memory\n");
system("ipcs -m");
waitpid(pid,NULL,0);
printf("finished\n");
}
exit(0);
}