shmdt() 与 shmctl() 的区别?
操作共享内存,我们用到了下面的函数
==============================================
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmid = shmget( key_t shmkey , int shmsize , int flag
);
(void *)shmaddr = shmat( int shmid , char *shmaddr , int shmflag
);
int shmdt( char *shmaddr );
【shmget】—— 是用来开辟/指向一块共享内存的函数
参数:
shmkey
是这块共享内存的标识符,如果是IPC_PRIVATE,则表示使用系统分配的键值创建;
shmsize 申请内存大小
flag
标志、权限;
当只有IPC_CREAT选项打开时,不管是否已存在该块共享内存,则都返回该共享内存的ID,若不存在则创建共享内存;
当只有IPC_EXCL选项打开时,不管有没有该块共享内存,shmget()都返回-1;(即:单独使用该标志无意义)
当IPC_CREAT | IPC_EXCL时,
如果没有该块共享内存,则创建,并返回共享内存ID,若已有该块共享内存,则返回-1;
返回值:
shmid 内存标识的ID
【shmat】—— 链接上指定ID标识的共享内存
参数:
shmid
内存标识ID,由shmget()函数返回;
shmaddr
(输出参数)共享内存的首地址,同该函数返回值一致;
shmflag SHM_RDONLY 只读, 0
可读写;(SHM_COPY\SHM_MAP\SHM_RND不在此说明)
【shmdt】—— 断开链接的共享内存指针
参数:
shmaddr
调用函数shmat()链接上共享内存的指针;
当一个进程不再需要共享内存段时,它将调用shmdt()系统调用取消这个段,但是,这并不是从内核真正地删除这个段,而是把相关shmid_ds结构的 shm_nattch域的值减1,当这个值为0时,内核才从物理上删除这个共享段
========================================================
用来控制共享内存的shmctl()函数如下:
=========================================================
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl( int shmid , int cmd , struct shmid_ds *buf );
【shmctl】—— 控制共享内存
参数:
shmid 共享内存标识ID;
cmd
IPC_STAT 得到共享内存的状态
IPC_SET 改变共享内存的状态
IPC_RMID 删除共享内存
buf
是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定;
struct shmid_ds结构体
struct shmid_ds {
struct ipc_perm shm_perm;
int shm_segsz;
time_t shm_atime;
time_t shm_dtime;
time_t shm_ctime;
unsigned short shm_cpid;
unsigned short shm_lpid;
short shm_nattch;
unsigned short shm_npages;
unsigned long *shm_pages;
struct vm_area_struct *attaches;
};
IPC_RMID
命令实际上不从内核删除一个段,而是仅仅把这个段标记为删除,实际的删除发生在最后一个进程离开这个共享段时。
==========================================================
总结:
shmdt(addr)使进程中的shmaddr指针无效化,不可以使用,但是保留空间。
shmctl(shmid,IPC_RMID,0) 删除共享内存,彻底不可用,释放空间。