一,共享内存介绍
共享内存是三个IPC(Inter-Process Communication)机制中的一个,它允许两个不相关的进程访问同一个逻辑内存。
 

二、共享内存使用的函数

#include <sys/shm.h>
  int shmget(key_t key, size_t size, int shmflg);
  void *shmat(int shm_id, const void *shm_addr, int shmflg);
  int shmdt(const void *shm_addr);
  int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
 

1. shmget函数
该函数用来创建共享内存:
      int shmget(key_t key, size_t size, int shmflg);
参数:
  key : 和信号量一样,程序需要提供一个参数key,它有效地为共享内存段命名。有一个特殊的键值IPC_PRIVATE, 它用于创建一个只属于创建进程的共享内存,通常不会用到。
  size: 以字节为单位指定需要共享的内存容量。
  shmflag: 包含9个比特的权限标志,它们的作用与创建文件时使用的mode标志是一样。由IPC_CREAT定义的一个特殊比特必须和权限标志按位或才能创建一个新的共享内存段。

NOTE:
  权限标志对共享内存非常有用,因为它允许一个进程创建的共享内存可以被共享内存的创建者所拥有的进程写入,同时其它用户创建的进程只能读取共享内存。
  我们可以利用这个功能来提供一种有效的对数据进行只读访问的方法,通过将数据放共享内存并设置它的权限,就可以避免数据被其他用户修改。

返回值:
创建成功,则返回一个非负整数,即共享内存标识;
如果失败,则返回-1.

2. shmat函数
第一次创建共享内存段时,它不能被任何进程访问。要想启动对该内存的访问,必须将其连接到一个进程的地址空间。
这个工作由shmat函数完成:
    void *shmat(int shm_id, const void *shm_addr, int shmflg);
参数:
  shm_id : 由shmget返回的共享内存标识。
  shm_add: 指定共享内存连接到当前进程中的地址位置。它通常是一个空指针, 表示让系统来选择共享内存出现的地址。
  shmflg : 是一组标志。它的两个可能取值是:SHM_RND, 和shm_add联合使用,用来控制共享内存连接的地址。SHM_RDONLY, 它使连接的内存只读
         
返回值:
如果调用成功, 返回一个指向共享内存第一个字节的指针;
如果失败,返回-1.

NOTE:
  共享内存的读写权限由它的属主(共享内存的创建者),
  它的访问权限和当前进程的属主决定。
  共享内存的访问权限类似于文件的访问权限。

3. shmdt函数
将共享内存从当前进程中分离。
    int shmdt(const void *shm_addr);
  shm_addr: shmat返回的地址指针。
成功时,返回0,
失败时,返回-1.

NOTE:
  共享内存分离并未删除它,
  只是使得该共享内存对当前进程不再可用。

4. shmctl函数
共享内存的控制函数
    int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
   shmid_ds结构至少包含以下成员:
    struct shmid_ds {
      uid_t shm_perm.uid;
      uid_t shm_perm.gid;
      mode_t shm_perm.mode;
    }
参数:
  shm_id : 是shmget返回的共享内存标识符。
  command: 是要采取的动作,
         它可以取3个值:
    IPC_STAT  把shmid_ds结构中的数据设置为共享内存的当前关联值
    IPC_SET   如果进程有足够的权限, 就把共享内存的当前关联值设置为shmid_ds结构中给出的值
    IPC_RMID  删除共享内存段
  buf  : 是一个指针,包含共享内存模式和访问权限的结构。

返回值:
成功时,返回0,
失败时,返回-1

例:生产者和消费者实例

头文件:shm_com.h

shm1.c 生产者程序通过它向消费者程序输入数据。

shm2.c 消费者将创建一个共享内存段,然后把写到它里面的数据都显示出来。

 #define TEXT_SZ 2048
 struct shared_use_st {
      int written;
      char some_text[TEXT_SZ];
  };

shm_com.h

 //shm1.c 生产者程序通过它向消费者程序输入数据。
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/shm.h>
 #include "shm_com.h"
 int main()
 {
       ;
       ;
       struct shared_use_st *shared_stuff;
       char buffer[BUFSIZ];
       int shmid;

       shmid = shmget((key_t),  | IPC_CREAT);
       )
       {
         fprintf(stderr, "shmget failed\n");
         exit(EXIT_FAILURE);
       }

       shared_memory = shmat(shmid, (, );
       )
       {
         fprintf(stderr, "shmat failed\n");
         exit(EXIT_FAILURE);
       }

       printf("Memory attached at %X\n", (int)shared_memory);

       shared_stuff = (struct shared_use_st *)shared_memory;
       while(running)
       {
         )
         {
           sleep();
           printf("waiting for client...\n");
         }
         printf("Enter some text: ");
         fgets(buffer, BUFSIZ, stdin);

         strncpy(shared_stuff->some_text, buffer, TEXT_SZ);
         shared_stuff->written = ;

         ) == ) {
           running = ;
         }
       }

       ) {
         fprintf(stderr, "shmdt failed\n");
         exit(EXIT_FAILURE);
       }

       exit(EXIT_SUCCESS);
     }

shm1.c

 //shm2.c 消费者将创建一个共享内存段,然后把写到它里面的数据都显示出来。
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/shm.h>
 #include "shm_com.h"
 int main()
 {
     ;
     ;
     struct shared_use_st *shared_stuff;
     int shmid;
     srand((unsigned int)getpid());
     shmid = shmget((key_t),  | IPC_CREAT);

     ) {
     fprintf(stderr, "shmget failed\n");
     exit(EXIT_FAILURE);
     }

     //现在,让程序可以访问这个共享内存:
     shared_memory = shmat(shmid, (, );

     ) {
     fprintf(stderr, "shmat failed\n");
     exit(EXIT_FAILURE);
     }
     printf("Memory attached at %X\n", (int)shared_memory);

     //程序的下一部分将shared_memory分配给shared_stuff,然后它输出written中的文本。
     //循环将一直执行到在written中找到end字符串为止。
     //sleep调用强迫消费者程序在临界区域多待一会,
     //让生产者程序等待:

     shared_stuff = (struct shared_use_st *)shared_memory;
     shared_stuff->written = ;

     while(running)
     {
     if (shared_stuff->written)
     {
       printf("You wrote: %s", shared_stuff->some_text);

       sleep( rand() %  ); /* make the other process wait for us ! */
       shared_stuff->written = ;

       ) == ) {
         running = ;
       }
     }
     }

     //最后,共享内存被分离,然后被删除:
     )
     {
     fprintf(stderr, "shmdt failed\n");
     exit(EXIT_FAILURE);
     }

     ) == -)
     {
     fprintf(stderr, "shmctl(IPC_RMID) failed\n");
     exit(EXIT_FAILURE);
     }

     exit(EXIT_SUCCESS);
 }

shm2.c

程序解析:
消费者程序
1)创建共享内存段,
2)然后将它连接到它自己的地址空间中,
3)我们在共享内存的开始处使用了一个结构shared_use_st.该结构中有个标志written,当共享内存中有数据写入时,就设置这个标志。
这个标志被设置时,程序就从共享内存中读取文本,将它打印出来,然后清除这个标志,表示已经读完数据。我们用一个特殊字符串end来退出循环。
4)程序分离共享内存段并删除它。

生产者程序
1)使用相同的键值1234来取得并连接同一个共享内存段,
2)然后提示用户输入一些文本。如果标志written被设置,生产者就知道消费都进程还未读完上一次的数据,因此就继续等待。
3)当其它进程清除了这个标志后,生产者写入新的数据并设置这个标志。它还使用字符串end来终止并分离共享内存段。

这里提供的同步标志written,它是一个非常缺乏效率的忙等待(不停地循环)

IPC编程之共享内存的更多相关文章

  1. linux编程之共享内存

    linux 进程间通信(IPC)包括3种机制:消息队列.信号量.共享内存.消息队列和信号量均是内核空间的系统对象,经由它们 的数据需要在内核和用户空间进行额外的数据拷贝:而共享内存和访问它的所有应用程 ...

  2. Linux IPC System V 共享内存

    模型 #include<sys/types.h> #include<sys/ipc.h> #include<sys/shm.h> ftok() //获取key值 s ...

  3. Linux IPC实践(8) --共享内存/内存映射

    概述 共享内存区是最快的IPC形式.一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据(如图). 共享内存 VS ...

  4. Unix IPC之基于共享内存的计数器

    目的 本文主要实现一个基于共享内存的计数器,通过父子进程对其访问. 本文程序需基于<<Unix网络编程-卷2>>的环境才能运行.程序中大写开头的函数为其小写同名函数的包裹函数, ...

  5. Linux环境编程之共享内存区(一):共享内存区简单介绍

    共享内存区是可用IPC形式中最快的.一旦内存区映射到共享它的进程的地址空间,进程间数据的传递就不再涉及内核.然而往该共享内存区存放信息或从中取走信息的进程间通常须要某种形式的同步.不再涉及内核是指:进 ...

  6. IPC 进程间通信方式——共享内存

    共享内存 共享内存区域是被多个进程共享的一部分物理内存. 多个进程都可以把共享内存映射到自己的虚拟空间.所有用户空间的进程要操作共享内存,都要将其映射到自己的虚拟空间,通过映射的虚拟内存空间地址去操作 ...

  7. linux网络编程之共享内存介绍

    今天是个好日子,洋人之节乃全球同庆,圣诞一来感觉就要过年了,不过今晚心情有点打折扣,给心爱的人打电话没有打通,本想在平安夜送上快乐的祝福给她,糟糕的心情让自己好像泄了气的皮球一样,无精打彩,心情灰暗, ...

  8. System V IPC 之共享内存

    IPC 是进程间通信(Interprocess Communication)的缩写,通常指允许用户态进程执行系列操作的一组机制: 通过信号量与其他进程进行同步 向其他进程发送消息或者从其他进程接收消息 ...

  9. C 共享内存封装

    引言 - 背景 2016 年写过一篇关于 linux 共享内存 shm api 扫盲文. C扩展 从共享内存shm到memcache外部内存 比较简单. 没有深入分析(能力有限, 也深入分析不了). ...

随机推荐

  1. 关于mosquitto_internal.h:40:25:#include <uuid/uuid.h> 致命错误的解决

    一.安装mosquitto1.4的时候使用make的时候报以下错误: mosquitto_internal.h:40:25: 致命错误:openssl/ssl.h:没有那个文件或目录 #include ...

  2. Linux基础系列:常用命令(8)_shell script

    一.什么是shell script 将OS命令堆积到可执行的文件里,由上至下的顺序执行文本里的OS命令 就是脚本了. 再加上些智能(条件/流控)控制,就变成了智能化脚本了 二.变量命名规则 以字母或下 ...

  3. LeetCode:字母异位词分组【16】

    LeetCode:字母异位词分组[16] 题目描述 给定一个字符串数组,将字母异位词组合在一起.字母异位词指字母相同,但排列不同的字符串. 示例: 输入: ["eat", &quo ...

  4. iOS 在视图控制器里面判断 应用程序的前台 后台切换 UIViewController

    1.时机  用户点击home 键  应用退到后台 再次点击进入前台  在UIViewController里面 控制器如何获取相关的事件? 2.需求 (1)NSTimer   在应用程序进入后台 10秒 ...

  5. 0425 os模块 ,模块和包

    os模块 *os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirname") 改变当前脚本工作目录:相当于shell下cd o ...

  6. 【Flask模板】include标签

    # include标签:1. 这个标签相当于是直接将指定的模版中的代码复制粘贴到当前位置.2. `include`标签,如果想要使用父模版中的变量,直接用就可以了,不需要使用`with context ...

  7. echarts相关设置

    1.显示隐藏工具栏 注释toolbox即可 /*    toolbox: {         show : true,         feature : {             dataView ...

  8. Delphi程序的自动升级功能的实现(AutoUpdate使用指南)

    在UtiMnid组件下,利用auAutoUpgrader实现自动升级(已经测试通过) 第一步:下载AutoUpgrader.Pro.v4.6.4. 第二步:打开AutoUpgrader.Pro.v4. ...

  9. Hive split分割后获取最后一段

    ----------------------------------------- 如果只看解决方法,直接看最后... ---------------------------------------- ...

  10. spring学习(3)

    bean的声明周期 为什么把生命周期当做一个重点? Servlet->servlet生命周期 Servlet生命周期分为三个阶段: 1:初始化阶段,调用init()方法 2:响应客户请求阶段,调 ...