在很久以前,我们学过一个函数 fcntl,当时学习它时挺费劲,因为一个函数,竟然有如此多的功能。今天要学习 shmctl 函数,也是一样。这种以 cntl/ctl 为后缀的函数,往往都具备这样的特性:它们都有一个命令控制参数,你传递不同的命令,这个函数有具备着不同的功能,可谓身兼数职说的就是它吧。
1. shmctl 函数
1.1 函数原型
这个函数的参数 shmid 是 ipc 内核对象的 id。cmd 是命令,这里只介绍 IPC_STAT, IPC_SET 和 IPC_RMID 三个命令。其中 IPC_RMID 命令表示删除内核对象。实际上不只是针对 shmctl 这个函数,消息队列和信号量的控制函数(msgctl 和 semctl) 的命令也是这样。
先看看第三个参数 shmid_ds 结构体。
1.2 shmid_ds 结构体
有时候,我们需要获取 IPC 内核对象的相关信息,这时候要怎么办呢? 毕竟 ipc 内核对象它位于内核空间中,普通用户程序根本无法直接访问,为此 linux 提供了这样的结构体 shmid_ds 给用户态的程序使用。shmctl 函数可以将位于内核空间的 ipc 内核对象的信息拷贝一份给用户空间的 shmid_ds,也可以通过将此结构体中的信息拷贝到内核空间用来设置 ipc 内核对象,具体是哪种情况依赖于参数 cmd。
当 cmd = IPC_STAT 的时候, 第三个参数 buf 用于接收返回值,当 cmd = IPC_SET 的时候,第三个参数用于传递值并设置内核对象。当 cmd = IPC_RMID 的时候,第三个参数被忽略,可以直接传 NULL.
该结构体的详细内容见注释。
其中成员 shm_perm 是所有 System V IPC 内核对象都包含的,它的结构如下:
2. 实验
下面的程序 shmctl 可以用来创建、删除内核对象,也可以挂接、卸载共享内存,还可以打印、设置内核对象信息。具体使用方法具体见下面的说明:
-
./shmctl -c
: 创建内核对象。 -
./shmctl -d
: 删除内核对象。 -
./shmctl -v
: 显示内核对象信息。 -
./shmctl -s
: 设置内核对象(将权限设置为 0600)。 -
./shmctl -a
: 挂接和卸载共享内存(挂接 5 秒后,再执行 shmdt,然后退出)。
shmctl 函数的代码见 2.5 节。
2.1 创建内核对象
图1 创建内核对象,打印内核对象信息
2.2 设置内核对象
图2 将内核对象权限设置为 0600
2.3 挂接后内核对象信息
先在另一个终端执行 ./shmctl -a
,然后在当前终端执行./shmctl -v
(注意手速,5秒内要搞定)。
图3 挂接共享内存后 ipc 内核对象的信息
2.4 卸载后内核对象信息
当 2.3 节上的 ./shmctl -a
结束后,再执行一次 ./shmctl -v
.
图4 卸载共享内存后 ipc 内核对象的信息
2.5 shmctl 程序代码
这段代码比较长,你可以直接复制过去进行编译。
3. 总结
- 知道如何获取 ipc 内核对象的信息
- 掌握 shmctl 函数的使用