shmget
int shmget(key_t key, size_t size, int flag);
key: 标识符的规则
size:共享存储段的字节数
flag:读写的权限
返回值:成功返回共享存储的id,失败返回-1

key_t key
-----------------------------------------------
    key标识共享内存的键值: 0/IPC_PRIVATE。 当key的取值为IPC_PRIVATE,则函数shmget()将创建一块新的共享内存;如果key的取值为0,而参数shmflg中设置了IPC_PRIVATE这个标志,则同样将创建一块新的共享内存。

在IPC(InterProcess Communication)的通信模式下,不管是使用消息队列还是共享内存,甚至是信号量,每个IPC的对象(object)都有唯一的名字,称为“键”(key)。通过“键”,进程能够识别所用的对象。“键”与IPC对象的关系就如同文件名称之于文件,通过文件名,进程能够读写文件内的数据,甚至多个进程能够共用一个文件。而在IPC的通讯模式下,通过“键”的使用也使得一个IPC对象能为多个进程所共用。
    Linux系统中的所有表示System V中IPC对象的数据结构都包括一个ipc_perm结构,其中包含有IPC对象的键值,该键用于查找System V中IPC对象的引用标识符。如果不使用“键”,进程将无法存取IPC对象,因为IPC对象并不存在于进程本身使用的内存中。
    通常,都希望自己的程序能和其他的程序预先约定一个唯一的键值,但实际上并不是总可能的成行的,因为自己的程序无法为一块共享内存选择一个键值。因此,在此把key设为IPC_PRIVATE,这样,操作系统将忽略键,建立一个新的共享内存,指定一个键值,然后返回这块共享内存IPC标识符ID。而将这个新的共享内存的标识符ID告诉其他进程可以在建立共享内存后通过派生子进程,或写入文件或管道来实现。

int size(单位字节Byte)
-----------------------------------------------
    size是要建立共享内存的长度。所有的内存分配操作都是以页为单位的。所以如果一段进程只申请一块只有一个字节的内存,内存也会分配整整一页(在i386机器中一页的缺省大小PACE_SIZE=4096字节)这样,新创建的共享内存的大小实际上是从size这个参数调整而来的页面大小。即如果size为1至4096,则实际申请到的共享内存大小为4K(一页);4097到8192,则实际申请到的共享内存大小为8K(两页),依此类推。

int shmflg
-----------------------------------------------
    shmflg主要和一些标志有关。其中有效的包括IPC_CREAT和IPC_EXCL,它们的功能与open()的O_CREAT和O_EXCL相当。
    IPC_CREAT   如果共享内存不存在,则创建一个共享内存,否则打开操作。
    IPC_EXCL    只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误。

如果单独使用IPC_CREAT,shmget()函数要么返回一个已经存在的共享内存的操作符,要么返回一个新建的共享内存的标识符。如果将IPC_CREAT和IPC_EXCL标志一起使用,shmget()将返回一个新建的共享内存的标识符;如果该共享内存已存在,或者返回-1。IPC_EXEL标志本身并没有太大的意义,但是和IPC_CREAT标志一起使用可以用来保证所得的对象是新建的,而不是打开已有的对象。对于用户的读取和写入许可指定SHM_R和SHM_W,(SHM_R>3)和(SHM_W>3)是一组读取和写入许可,而(SHM_R>6)和(SHM_W>6)是全局读取和写入许可。

需要注意的是,使用参数要加上 | 0666 作为校验,在有些Linux系统中,如果不加此校验,则不能顺利获取共享空间的值(如Ubuntu)。此外,有两个常用参数,一般要同时出现,他们是:S_IRUSH | S_IWUSR 。由于这两个参数非常常用,程序员一般做这样的操作
  #define PERM S_IRUSR | S_IWUSR | IPC_CREAT
  这样一来,第三个参数就可以直接用PERM来表示了!

返回值
-----------------------------------------------
成功返回共享内存的标识符;不成功返回-1,errno储存错误原因。
    EINVAL        参数size小于SHMMIN或大于SHMMAX。
    EEXIST        预建立key所致的共享内存,但已经存在。
    EIDRM         参数key所致的共享内存已经删除。
    ENOSPC        超过了系统允许建立的共享内存的最大值(SHMALL )。
    ENOENT        参数key所指的共享内存不存在,参数shmflg也未设IPC_CREAT位。
    EACCES        没有权限。
    ENOMEM        核心内存不足。

struct shmid_ds
-----------------------------------------------
    shmid_ds数据结构表示每个新建的共享内存。当shmget()创建了一块新的共享内存后,返回一个可以用于引用该共享内存的shmid_ds数据结构的标识符。

include/linux/shm.h

struct shmid_ds { 
        struct ipc_perm    shm_perm;      /* operation perms */ 
        int                shm_segsz;     /* size of segment (bytes) */ 
        __kernel_time_t    shm_atime;     /* last attach time */ 
        __kernel_time_t    shm_dtime;     /* last detach time */ 
        __kernel_time_t    shm_ctime;     /* last change time */ 
        __kernel_ipc_pid_t shm_cpid;      /* pid of creator */ 
        __kernel_ipc_pid_t shm_lpid;      /* pid of last operator */ 
        unsigned short     shm_nattch;    /* no. of current attaches */ 
        unsigned short     shm_unused;    /* compatibility */ 
        void               *shm_unused2; /* ditto - used by DIPC */ 
        void               *shm_unused3; /* unused */ 
    };

struct ipc_perm
-----------------------------------------------
    对于每个IPC对象,系统共用一个struct ipc_perm的数据结构来存放权限信息,以确定一个ipc操作是否可以访问该IPC对象。

struct ipc_perm { 
        __kernel_key_t   key; 
        __kernel_uid_t   uid; 
        __kernel_gid_t   gid; 
        __kernel_uid_t   cuid; 
        __kernel_gid_t   cgid; 
        __kernel_mode_t mode; 
        unsigned short   seq; 
};
//----------------------------------------

shmat
void *shmat(int shmid, const void *addr, int flag);
shmid:共享存储的id
addr:一般为0,表示连接到由内核选择的第一个可用地址上,否则,如果flag没有指定SHM_RND,则连接到addr所指定的地址上,如果flag为SHM_RND,则地址取整
flag:如前所述,一般为0
返回值:如果成功,返回共享存储段地址,出错返回-1
共享存储器的执行方式是将一个储存器区段标记为共用,这时各进程可以把这个区段映射到该进程本身的虚拟地址里。建立共享存储器可通过shmget系统调用,shmget执行后,核心程序就保留一块指定大小的空间,同时关于此共享存储器的一切数据,如区段的长度,区段的存取权,区段建立者的进程识别码等存入一个叫shmid_ds的结构。现在共享存储器虽然已经建立了,可是仍无法连上它,这时就须通过shmat系统调用得到一个指向共享存储器基址的指针,通过此指针,就可以如同于操作一般存储器似的取用共享存储器。shmdt进行相反的工作,用来脱离已连上的共享存储器。

shmdt
int shmdt(void *addr);
addr:共享存储段的地址,以前调用shmat时的返回值
shmdt将使相关shmid_ds结构中的shm_nattch计数器值减1

当一个进程不再需要共享内存段时,它将调用shmdt()系统调用取消这个段,但是,这并不是从内核真正地删除这个段,而是把相关shmid_ds结构的 shm_nattch域的值减1,当这个值为0时,内核才从物理上删除这个共享段

shmctl
int shmctl(int shmid,int cmd,struct shmid_ds *buf)
shmid:共享存储段的id
cmd:一些命令

IPC_STAT 得到共享内存的状态
        IPC_SET 改变共享内存的状态
        IPC_RMID 删除共享内存

IPC_RMID 命令实际上不从内核删除一个段,而是仅仅把这个段标记为删除,实际的删除发生在最后一个进程离开这个共享段时。

请注意,共享内存不会随着程序结束而自动消除,要么调用shmctl删除,要么自己用手敲命令去删除,否则永远留在系统中。

实例:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <errno.h>
  5. #include <unistd.h>
  6. #include <sys/stat.h>
  7. #include <sys/types.h>
  8. #include <sys/ipc.h>
  9. #include <sys/shm.h>
  10. #define PERM S_IRUSR|S_IWUSR
  11. int main(int argc,char **argv){
  12. int shmid;
  13. char *p_addr,*c_addr;
  14. if(argc!=2){
  15. fprintf(stderr,"Usage:%s\n\a",argv[0]);
  16. exit(1);
  17. }
  18. if((shmid=shmget(IPC_PRIVATE,1024,PERM))==-1){
  19. fprintf(stderr,"Create Share Memory Error:%s\n\a",strerror(errno));
  20. exit(1);
  21. }
  22. if(fork()){
  23. p_addr=shmat(shmid,0,0);
  24. memset(p_addr,'\0',1024);
  25. strncpy(p_addr,argv[1],1024);
  26. exit(0);
  27. }else{
  28. c_addr=shmat(shmid,0,0);
  29. printf("Client get %s",c_addr);
  30. exit(0);
  31. }
  32. }

这个程序是父进程将参数写入到共享内存,然后子进程把内容读出来.最后我们要使用ip

crm 释放资源的.先用ipcs 找出ID 然后用ipcrm shm ID 删除.

linux shmget shmctl的更多相关文章

  1. 浅析Linux下进程间通信:共享内存

    浅析Linux下进程间通信:共享内存 共享内存允许两个或多个进程共享一给定的存储区.因为数据不需要在客户进程和服务器进程之间复制,所以它是最快的一种IPC.使用共享内存要注意的是,多个进程之间对一给定 ...

  2. Linux进程通信之System V共享内存

    前面已经介绍过了POSIX共享内存区,System V共享内存区在概念上类似POSIX共享内存区,POSIX共享内存区的使用是调用shm_open创建共享内存区后调用mmap进行内存区的映射,而Sys ...

  3. Linux 驱动开发

    linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...

  4. Linux进程间通信(六):共享内存 shmget()、shmat()、shmdt()、shmctl()

    下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式 ...

  5. ubuntu linux c学习笔记----共享内存(shmget,shmat,shmdt,shmctl)

    shmget int shmget(key_t key, size_t size, int flag); key: 标识符的规则 size:共享存储段的字节数 flag:读写的权限 返回值:成功返回共 ...

  6. 【转载】Linux进程间通信(六):共享内存 shmget()、shmat()、shmdt()、shmctl()

    来源:https://www.cnblogs.com/52php/p/5861372.html 下面将讲解进程间通信的另一种方式,使用共享内存. 一.什么是共享内存 顾名思义,共享内存就是允许两个不相 ...

  7. linux 共享内存 shmat,shmget,shmdt,shmctl

    shmget int shmget(key_t key, size_t size, int flag);//开辟一段共享内存 key_t key :标识符的规则() size_t size :共享内存 ...

  8. 共享内存创建shmget控制操作shmat,shmctl

    1.共享内存的数据结构 共享内存就是分配一块能被其他进程访问的内存.每个共享内存段在内核中维护着一个内部结构: struct shmid_ds { struct ipc_perm shm_perm; ...

  9. Linux C 收藏

    某招聘要求:熟悉高性能分布式网络服务端设计开发,熟悉epoll.多线程.异步IO.事件驱动等服务端技术: <UNIX环境高级编程(第3版)>apue.h等源码文件的编译安装 <UNI ...

随机推荐

  1. ReactiveCocoa概念解释进阶篇

    1.ReactiveCocoa常见操作方法介绍 1.1 ReactiveCocoa操作须知 所有的信号(RACSignal)都可以进行操作处理,因为所有操作方法都定义在RACStream.h中,因此只 ...

  2. cppoop作业:Inheritance+Composition 關係下的構造和析構

    Inheritance+Composition 關係下的構造和析構 哪个的ctor先被调用. 父类先于组件类调用 构造函数

  3. 有重复元素的排列(DFS)

    题目描述: 设R={ r1, r2 , …, rn}是要进行排列的n个元素.其中元素r1, r2 , …, rn均为小写字母并且可能相同.试设计一个算法,列出R的所有不同排列. 给定n 以及待排列的n ...

  4. php进行文件的强制下载

    浏览器下载文件,例如在浏览器中可以直接打开的文件(.gif /.txt等).在进行文件下载操作时,默认是通过浏览器直接打开,而不是下载保存文件.并且通过这种方法下载文件可以不暴漏下载文件所在的路径,可 ...

  5. centos7安装pgsql及操作命令

    1.下载所需要的数据库版本https://yum.postgresql.org/repopackages.php 2.安装数据库版本包 yum install -y https://download. ...

  6. Altium Designer入门学习笔记2:使用原创客3D元件库

    请自行淘宝购买: 元件库列表(2018年11月27日): 问题一:在项目库或已安装的库中找不到? 将"原创客"提供的文件全部添加到libraries中!"原创客" ...

  7. LeetCode(5)Longest Palindromic Substring

    题目 Given a string S, find the longest palindromic substring in S. You may assume that the maximum le ...

  8. poj 2385 树上掉苹果问题 dp算法

    题意:有树1 树2 会掉苹果,奶牛去捡,只能移动w次,开始的时候在树1 问最多可以捡多少个苹果? 思路: dp[i][j]表示i分钟移动j次捡到苹果的最大值 实例分析 0,1  1,2...说明 偶数 ...

  9. hierarchy viewer不能获取userbuild手机版本的UI布局

    步骤很详细:http://maider.blog.sohu.com/255485243.html 其中的第7步命令需要更改为: java -jar smali-2.0.3.jar ./out -o c ...

  10. 逻辑与(&)和短路与(&&)的关系

    逻辑与(&)和短路与(&&)在运算上对条件的结果判断不会产生影响,但会对条件判断的运算有影响.关键在于,逻辑与(&)在运算时会连续运算所有需要判断的命令.但短路与当遇到 ...