1.什么是共享内存
共享内存从字面意义解释就是多个进程可以把一段内存映射到自己的进程空间,以此来实现数据的共享以及传输,这也是所有进程间通信方式中最快的一种。共享内存是存在于内核级别的一种资源,在shell中可以使用ipcs命令来查看当前系统IPC中的状态,在文件系统中/proc目录下有对其描述的相应文件。
在系统内核为一个进程分配内存地址时,通过分页机制可以让一个进程的物理地址不连续,同时也可以让一段内存同时分配给不同的进程。共享内存机制就是通过该原理来实现的,共享内存机制只是提供数据的传送,如何控制服务器端和客户端的读写操作互斥,这就需要一些其他的辅助工具,例如,记录锁概念.
2 共享内存系统函数
共享内存是存在于内核级别的一种资源,在shell中可以使用ipcs命令来查看当前系统IPC中的状态,在文件系统/proc目录下有对其描述的相应文件。
1) 函数shmget:可以创建或打开一块共享内存区。函数原型如下:
#include <sys/shm.h> int shmget( key_t key, size_t size, int flag ); |
参数说明:函数中参数key用来变换成一个标识符,而且每一个IPC对象与一个key相对应。当新建一个共享内存段时,size参数为要请求的内存长度(以字节为单位)。
注意:内核是以页为单位分配内存,当size参数的值不是系统内存页长的整数倍时,系统会分配给进程最小的可以满足size长的页数,但是最后一页的剩余部分内存是不可用的。
当打开一个内存段时,参数size的值为0。参数flag中的相应权限位初始化ipc_perm结构体中的mode域。同时参数flag是函数行为参数,它指定一些当函数遇到阻塞或其他情况时应做出的反应。
2) 函数shmctl:可以对共享内存段进行多种操作,其函数原型如下:
#include <sys/shm.h> int shmctl( int shm_id, int cmd, struct shmid_ds *buf ); |
参数说明:函数中参数sh_mid为所要操作的共享内存段的标识符,struct shmid_ds型指针参数buf的作用与参数cmd的值相关,参数cmd指明了所要进行的操作,其解释如表14-5所示。
3) 函数shmat:将一个存在的共享内存段连接到本进程空间,其函数原型如下:
#include <sys/shm.h> void *shmat( int shm_id, const void *addr, int flag ); |
参数说明:函数中参数shm_id指定要引入的共享内存,参数addr与flag组合说明要引入的地址值,通常只有2种用法,addr为0,表明让内核来决定第1个可以引入的位置。addr非零,并且flag中指定SHM_RND,则此段引入到addr所指向的位置(此操作不推荐使用,因为不会只对一种硬件上运行应用程序,为了程序的通用性推荐使用第1种方法),在flag参数中可以指定要引入的方式(读写方式指定)。
说明:函数成功执行返回值为实际引入的地址,失败返回-1。shmat函数成功执行会将shm_id段的shmid_ds结构的shm_nattch计数器的值加1。
4) shmdt函数:当对共享内存段操作结束时,调用此函数,作用是将指定的共享内存段从当前进程空间中脱离出去。函数原型如下:
#include <sys/shm.h> int shmdt( void *addr); |
参数说明:参数addr是调用shmat函数的返回值,函数执行成功返回0,并将该共享内存的shmid_ds结构的shm_nattch计数器减1,失败返回-1。
附加:/*IPC操作时IPC_CREAT和IPC_EXCL选项的说明
IPC(包括消息队列,共享内存,信号量)的xxxget()创建操作时,可以指定IPC_CREAT和IPC_EXCL选项。
以共享内存为例:
当只有IPC_CREAT选项打开时,不管是否已存在该块共享内存,则都返回该共享内存的ID,若不存在则创建共享内存
当只有IPC_EXCL选项打开时,不管有没有该快共享内存,shmget()都返回-1
所以当IPC_CREAT | IPC_EXCL时, 如果没有该块共享内存,则创建,并返回共享内存ID。
若已有该块共享内存,则返回-1;*/
代码演示,实现功能为一个write。c实现往共享内存写东西,read。c负责读共享内训的东西
write.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <string.h>
#define LEN 1024
struct share
{
int written_use;
char msg[LEN];
};
int main()
{
int flag=1;
struct share *share_p;
void *temp;
int shmid;
char buf[LEN];
shmid=shmget((key_t)1234,sizeof(struct share),0666|IPC_CREAT);
if(shmid==-1)
{
printf("fail to shmget\n");
exit(1);
}
temp=shmat(shmid,(void*)0,0);
if(temp==(void*)-1)
{
printf("fail to shmat\n");
exit(1);
}
share_p=(struct share *)temp;
//share_p->written_use=1;
while(flag)
{
if(share_p->written_use==1)
{
sleep(1);
printf("Waiting......\n");
}
printf("Please input your mesage:");
fgets(buf,LEN,stdin);
strncpy(share_p->msg,buf,LEN);
share_p->written_use=1;
if(strncmp(share_p->msg,"end",3)==0)
{
flag=0;
}
}
if(shmdt(share_p)==-1)
{
printf("fail to shmdt\n");
exit(1);
}
return 0;
}
read.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#define LEN 1024
struct share_msg
{
int written_use;
char msg[LEN];
};
int main()
{
int flag=1;//判断何时退出
struct share_msg *share_p;
void *temp=(void *)0;//shmat函数成功执行返回值为实际引入的地址,类型为void *型
int shm_id;
shm_id=shmget((key_t)1234,sizeof(struct share_msg),0666|IPC_CREAT);
if(shm_id==-1)
{
printf("fail to shmget\n");
exit(1);
}
temp=shmat(shm_id,(void*)0,0);
if(temp==(void *)-1)
{
printf("fail to shmat\n");
exit(1);
}
share_p=(struct share_msg *)temp;
share_p->written_use=0;
while(flag)
{
if(share_p->written_use)
{
printf("Your write is :%s",share_p->msg);
sleep(1);
share_p->written_use=0;
if(strncmp(share_p->msg,"end",3)==0)
{
flag=0;
}
}
}
if(shmdt(share_p)==-1)
{
printf("fail to shmdt\n");
exit(1);
}
return 0;
}
代码演示:
参考过别人的东西,谢谢。