调用共享内存的方法《精通Unix下C语言编程与项目实践》之八

简介:
《精通Unix下C语言编程与项目实践》之八
共享内存的系统调用 
作者:朱云翔,胡平

14.2.1 共享内存的系统调用

共享内存的基本系统调用包括创建共享内存、映射共享内存和释放共享内存映射三种,分别由函数shmget、函数shmat和函数shmdt完成。

1. 共享内存的创建

Unix中,可以使用函数shmget来创建或获取共享内存,它的原型如下:
#include  <sys/shm.h>
int shmget (key_t key, size_t size, int shmflg);
函数shmget创建一个新的共享内存,或者访问一个已经存在的共享内存。参数key是共享内存的关键字。size指定了该共享内存的字节大小。参数shmflg的含义与消息队列函数msgget中参数msgflg的含义相类似。它的低9位决定了共享内存属主、属组和其它用户的访问权限,取值与表6-4的文件权限参数类似,但执行权限无意义。它的其它位指定了共享内存的创建方式,其取值与含义如表14-1所示:
14-1 消息队列创建方式参数
参数
描述
IPC_CREAT
创建共享内存,如果共享内存已经存在,就获取该共享内存的标识号。
IPC_EXCL
与宏IPC_CREAT一起使用,单独使用无意义,此时只能创建一个不存在的共享内存,如果内存已存在,则调用失败。
与消息队列类似,当参数key的取值为IPC_PRIVATE时,将创建关键字为0的共享内存,Unix内核可以同时存在多个关键字为0的共享内存。
函数shmget调用成功时,返回共享内存的标识符,否则返回-1
1. 创建关键字为0x1234,访问权限为0666,占用空间10K的共享内存,如果已存在则返回其标识号。
int shmid;
shmid = shmget(0x1234, 10*1024, 0666|IPC_CREAT);
2. 创建关键字为0x1234,访问权限为0666,占用空间10K的共享内存,如果已存在则报错。
int shmid;
shmid = shmget(0x1234, 10*1024, 0666|IPC_CREAT|IPC_EXCL);

2. 共享内存的映射

与消息队列和信号量不同,共享内存在获取标识号后,仍需调用函数shmat将共享内存段映射到进程地址空间后才可以访问。函数shmat的原型如下:
#include  <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
函数shmat将标识号为shmid共享内存映射到调用进程的地址空间中,映射的地址由参数shmaddrshmflg共同确定,其规则为:
(1) 如果参数shmaddr取值为NULL,系统将自动确定共享内存链接到进程空间的首地址。
(2) 如果参数shmaddr取值不为NULL且参数shmflg没有指定SHM_RND标志,系统将使用地址shmaddr链接共享内存。
(3) 如果参数shmaddr取值不为NULL且参数shmflg指定了SHM_RND标志位,系统将地址shmaddr对齐后链接共享内存。其中选项SHM_RND的意思是取整对齐,常数SHMLBA代表了低边界地址的倍数,公式“shmaddr - (shmaddr % SHMLBA)”的含义是将地址shmaddr移动到低边界地址的整数倍上。
以上规则可归纳如表14-2所示:
14-2 共享内存地址映射规则
shmaddr
shmflg
映射地址
NULL
 
系统自动
NULL
未置SHM_RND标志位
shmaddr
NULL
SHM_RND标志位
shmaddr - (shmaddr % SHMLBA)
【实践经验】在绝大多数情况下,我们指定参数shmaddr值为NULL,以便系统自动选择映射地址。
除了SHM_RND标志,参数shmflg还可以设置SHM_RDONLY标志位,此时共享内存将以只读的方式映射到内存地址中。
函数shmat调用成功时返回共享内存映射空间的起始地址,否则返回-1并置errno错误信息。
1. 将创建关键字为0x1234,占用空间10K的共享内存,链接到进程中。
int shmid;
char *pmat;
shmid = shmget(0x1234, 10*1024, 0666|IPC_CREAT);
pmat = shmat(shmid, 0, 0);
指针pmat指向共享内存映射空间的首地址。

3. 共享内存的释放

当进程不再需要共享内存时,可以使用函数shmdt释放共享内存映射,其原型如下:
#include  <sys/shm.h>
int shmdt(const void *shmaddr);
函数shmdt释放进程在地址shmaddr处映射的共享内存,参数shmaddr必须为函数shmget的返回值。本函数调用成功时返回0,否则返回-1
共享内存中有一个映射链接数,进程调用shmat成功时该链接数值自动增加1。调用函数shmdt并不能删除共享内存,它仅仅删除共享内存在进程中的一个链接,并将该共享内存映射数减1
共享内存可以被进程映射多次,每次映射的首地址是不一样的。进程结束时,系统将自动检查进程中映射的共享内存并释放该映射。
【实践经验】虽然系统会自动释放共享内存在进程中的链接,但显式的调用shmdt释放内存映射是一个良好的编程习惯。
1. 释放进程中地址paddr处的共享内存映射。
char *paddr;
int ret;
…………………………
ret = shmdt(paddr);
 

 本文转自 zhuyunxiang 51CTO博客,原文链接:http://blog.51cto.com/zhuyunxiang/137221,如需转载请自行联系原作者

相关文章
|
18天前
|
Java 数据库连接
Java中的内存泄漏排查与预防方法
Java中的内存泄漏排查与预防方法
|
16天前
|
缓存 算法 Java
Java面试题:深入探究Java内存模型与垃圾回收机制,Java中的引用类型在内存管理和垃圾回收中的作用,Java中的finalize方法及其在垃圾回收中的作用,哪种策略能够提高垃圾回收的效率
Java面试题:深入探究Java内存模型与垃圾回收机制,Java中的引用类型在内存管理和垃圾回收中的作用,Java中的finalize方法及其在垃圾回收中的作用,哪种策略能够提高垃圾回收的效率
19 1
|
21天前
|
存储 Java C语言
【C语言入门】初识C语言:掌握编程的基石
【C语言入门】初识C语言:掌握编程的基石
28 4
【C语言入门】初识C语言:掌握编程的基石
|
16天前
|
缓存 Prometheus 监控
Java面试题:如何监控和优化JVM的内存使用?详细讲解内存调优的几种方法
Java面试题:如何监控和优化JVM的内存使用?详细讲解内存调优的几种方法
34 3
|
21天前
|
存储 Java 程序员
【C语言入门】C语言入门:探索编程世界的基础概念
【C语言入门】C语言入门:探索编程世界的基础概念
26 2
|
29天前
|
Unix C语言
用C语言打造自己的Unix风格ls命令
用C语言打造自己的Unix风格ls命令
12 1
|
1月前
|
C语言
【海贼王编程冒险 - C语言海上篇】库函数怎样模拟实现?
【海贼王编程冒险 - C语言海上篇】库函数怎样模拟实现?
17 1
|
1月前
|
C语言
【海贼王编程冒险 - C语言海上篇】怎样用C语言实现简单的扫雷游戏?
【海贼王编程冒险 - C语言海上篇】怎样用C语言实现简单的扫雷游戏?
13 1
|
1月前
|
C语言
【海贼王编程冒险 - C语言海上篇】C语言如何实现简单的三子棋游戏?
【海贼王编程冒险 - C语言海上篇】C语言如何实现简单的三子棋游戏?
13 1
|
16天前
|
存储 设计模式 监控
Java面试题:简述JVM的内存结构,包括堆、栈、方法区等。栈内存优化的方法有 哪些?
Java面试题:简述JVM的内存结构,包括堆、栈、方法区等。栈内存优化的方法有 哪些?
22 0