共享内存的原理
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
共享内存
不同进程共享内存示意图
共享内存指在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存。由于多个CPU需要快速访问存储器,这样就要对存储器进行缓存(Cache)。任何一个缓存的数据被更新后,由于其他处理器也可能要存取,共享内存就需要立即更新,否则不同的处理器可能用到不同的数据。共享内存(shared memory)是 Unix下的多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。
目录
共享内存的创建
共享内存是存在于内核级别的一种资源,在shell中可以使用ipcs命令来查看当前系统IPC中的状态,在文件系统/proc目录下有对其描述的相应文件。函数shmget可以创建或打开一块共享内存区。函数原型如下:#include
int shmget( key_t key, size_t size, int flag );
函数中参数key用来变换成一个标识符,而且每一个IPC对象与一个key相对应。当新建一个共享内存段时,size参数为要请求的内存长度(以字节为单位)。
注意:内核是以页为单位分配内存,当size参数的值不是系统内存页长的整数倍时,系统会分配给进程最小的可以满足size长的页数,但是最后一页的剩余部分内存是不可用的。
当打开一个内存段时,参数size的值为0。参数flag中的相应权限位初始化ipc_perm结构体中的mode域。同时参数flag是函数行为参数,它指定一些当函数遇到阻塞或其他情况时应做出的反应。shmid_ds结构初始化如表14-4所示。
初始化
if (shm_id < 0 ) { /*创建共享内存*/
perror( "shmget" ) ;
exit ( 1 );
}
printf ( "successfully created segment : %d \n", shm_id ) ;
system( "ipcs -m"); /*调用ipcs命令查看IPC*/
exit( 0 );
}
(2)在shell中编译该程序如下:
$gcc create_shm.c–o create_shm
(3)在shell中运行该程序如下:
$./ create_shm
successfully created segment : 2752516
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 65536 root 600 393216 2 dest
0x00000000 2654209 root 666 4096 0
0x0056a4d5 2686978 root 600 488 1
0x0056a4d6 2719747 root 600 131072 1
0x00000000 2752516 root 666 4096 0
上述程序中使用shmget函数来创建一段共享内存,并在结束前调用了系统shell命令ipcs –m来查看当前系统IPC状态。
共享内存的操作
由于共享内存这一特殊的资源类型,使它不同于普通的文件,因此,系统需要为其提供专有的操作函数,而这无疑增加了程序员开发的难度(需要记忆额外的专有函数)。使用函数shmctl可以对共享内存段进行多种操作,其函数原型如下:
#include
int shmctl( int shm_id, int cmd, struct shmid_ds *buf );
函数中参数shm_id为所要操作的共享内存段的标识符,struct
shmid_ds型指针参数buf的作用与参数cmd的值相关,参数cmd指明了所要进行的操作,其解释如表14-5所示。
cmd参数详解
参数addr是调用shmat函数的返回值,函数执行成功返回0,并将该共享内存的shmid_ds结构的shm_nattch计数器减1,失败返回–1。
下面实例演示了操作共享内存段的流程。程序的开始部分先检测用户是否有输入,如出错则打印该命令的使用帮助。接下来从命令行读取将要引入的共享内存ID,使用shmat函数引入该共享内存,并在分离该内存之前睡眠3秒以方便查看系统IPC状态。
(1)在vi编辑器中编辑该程序如下:
程序清单14-9 opr_shm.c 操作共享内存段
#include
#include
#include
#include
#include
int main ( int argc, char *argv[] )
{
int shm_id ;
char * shm_buf;
if ( argc != 2 ){ /* 命令行参数错误 */
printf ( "USAGE: atshm
exit (1 );
}
shm_id = atoi(argv[1]); /*得到要引入的共享内存段*/
/*引入共享内存段,由内核选择要引入的位置*/
if ( (shm_buf = shmat( shm_id, 0, 0)) < (char *) 0 ){
perror ( "shmat" );
exit (1);
}
printf ( " segment attached at %p\n", shm_buf ); /*输出导入的位置*/
system("ipcs -m");
sleep(3); /* 休眠 */
if ( (shmdt(shm_buf)) < 0 ) { /*与导入的共享内存段分离*/
perror ( "shmdt");
exit(1);
}
printf ( "segment detached \n" );
system ( "ipcs -m " ); /*再次查看系统IPC状态*/
exit ( 0 );