共享内存:
是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容.
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同的进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间,进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。
采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的复制。对于像管道和消息队列等通信方式,则需要内核和用户空间进行四次的数据复制,而共享内存则只复制两次数据:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,在重新建立共享内存区域,而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。
共享内存实现分为两个步骤:
1、创建共享、打开共享内存,使用shmget函数
2、映射共享内存,将这段创建的共享内存映射到具体的进程空间去,使用shmat函数
3. 分离共享内存
4. 控制、删除共享内存
创建共享内存
Shmgt()
函数的作用:在内核中创建共享内存
函数的原型:int shmgt(key_t key, int size, int shmflg);
函数的头文件:#include <sys/types.h>、#include <sys/shm.h>
函数的参数:
Key:key标识共享内存的键值: 0/IPC_PRIVATE。 当key的取值为IPC_PRIVATE,则函 数shmget()将创建一块新的共享内存;如果key的取值为0,而参数shmflg中又设置IPC_PRIVATE这个标志,则同样会创建一块新的共享内存.
Size:创建的内存的大小。
Shmflg:类似open的权限。
函数逇返回值:
成功:返回共享内存段标识符。
出错:返回 -1.
映射共享内存
Shmat()
函数的作用:映射共享内存,映射到各自的内存空间。
函数的原型:char *shmat(int shmid, char * shmaddr, int flag);
函数的头文件:#include<sys/types.h>、#include<sys/ipc.h>、#include<sys/shm.h>
函数的参数:
Shmid:内存标识符
Shmaddr:映射共享内存到本进程的指定地址,如果为NULL则由内核进行
自动分配。
Flag:SHM_RDONLY:表示共享内存只读。
为0:表示共享内存可读写。
函数的返回值:
成功:返回共享内存映射到进程中的地址。
出错:返回 -1
当一个进程不再需要共享内存时,需要把它从进程地址空间中脱离。
共享内存解除映射
Shmdt()
函数的作用:撤销共享内存的映射。
函数的原型:int shmat(const void *shmaddr);
函数的参数:
Shmaddr:被映射的共享内存地址。
函数的返回值:
成功:返回0
出错:返回-1.
实例代码:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define PERM S_IRUSR|S_IWUSR
/*shared-memory */
int main(int argc,char **argv)
{
int shmid;
char *p_addr,*c_addr;
if(argc!=2)
{
fprintf(stderr,"Usage:%s\n\a",argv[0]);
exit(1);
}
/*creat shared-memory */
if((shmid=shmget(IPC_PRIVATE,1024,PERM))==-1)
{
fprintf(stderr,"Create Share Memory Error:%s\n\a",strerror(errno));
exit(1);
}
/*creat child fork */
if(fork()) /*father fork write*/
{
p_addr=shmat(shmid,0,0);
memset(p_addr,'\0',1024);
strncpy(p_addr,argv[1],1024);
wait(NULL); /*release resource, no care of end state*/
exit(0);
}
else /*child fork read*/
{
sleep(1); /*stop 1s*/
c_addr=shmat(shmid,0,0);
printf("Client get %s\n",c_addr);
exit(0);
}
}