CentOS下共享内存使用的常见陷阱详解

2020-01-30 15:42:50王振洲

(2) 如果参数shmaddr取值不为NULL且参数shmflg没有指定SHM_RND标志,系统将运用地址shmaddr链接共享内存。

(3) 如果参数shmaddr取值不为NULL且参数shmflg指定了SHM_RND标志位,系统将地址shmaddr对齐后链接共享内存。其中选项SHM_RND的意思是取整对齐,常数SHMLBA代表了低边界地址的倍数,公式“shmaddr – (shmaddr % SHMLBA)”的意思是将地址shmaddr移动到低边界地址的整数倍上。

Shmget创建共享内存,当key相同时,什么情况下会出错?

shmget() 用来创建一个共享内存区,或者访问一个已存在的共享内存区。该函数定义在头文件 linux/shm.h中,原型如下:

#include

#include

int shmget(key_t key, size_t size, int shmflg);

参数 key是由 ftok() 得到的键值;

参数 size 是以字节为单位指定内存的大小;

参数 shmflg 是操作标志位,它的一些宏定义如下:

IPC_CREATE : 调用 shmget 时,系统将此值与其他共享内存区的 key 进行比较,如果存在相同的 key ,说明共享内存区已存在,此时返回该共享内存区的标识符,否则新建一个共享内存区并返回其标识符。

IPC_EXCL : 该宏必须和 IPC_CREATE 一起使用,否则没意义。当 shmflg 取 IPC_CREATE | IPC_EXCL 时,表示如果发现内存区已经存在则返回 -1,错误代码为 EEXIST 。

注意,当创建一个新的共享内存区时,size 的值必须大于 0 ;如果是访问一个已经存在的内存共享区,则置 size 为 0 。

一般我们创建共享内存的时候会在一个进程中使用shmget来创建共享内存,

Int shmid = shmget(key, size, IPC_CREATE|0666);

而在另外的进程中,使用shmget和同样的key来获取到这个已经创建了的共享内存,

Int shmid = shmget(key, size, IPC_CREATE|0666);

如果创建进程和挂接进程key相同,而对应的size大小不同,是否会shmget失败?

Ø 已经创建的共享内存的大小是可以调整的,但是已经创建的共享内存的大小只能调小,不能调大

如:

shm_id = shmget(key,4194304,IPC_CREAT);

创建了一个4M大小的共享内存,如果这个共享内存没有删掉,我们再使用

shm_id = shmget(key,10485760,IPC_CREAT);

来创建一个10M大小的共享内存的时候,使用标准错误输出会有如下错误信息:

shmget error: Invalid argument

但是,如果我们使用:

shm_id = shmget(key,3145728,IPC_CREAT);

来创建一个3M大小的共享内存的时候,并不会输出错误信息,只是共享内存大小会被修改为3145728,这也说明,使用共享内存的时候,是用key来作为共享内存的唯一标识的,共享内存的大小不能区分共享内存。

这样会导致什么问题?

当多个进程都能创建共享内存的时候,如果key出现相同的情况,并且一个进程需要创建的共享内存的大小要比另外一个进程要创建的共享内存小,共享内存大的进程先创建共享内存,共享内存小的进程后创建共享内存,小共享内存的进程就会获取到大的共享内存进程的共享内存, 并修改其共享内存的大小和内容(留意下面的评论补充),从而可能导致大的共享内存进程崩溃。