共享内存

共享内存:共享内存就是分配一块能被其它进程访问的内存。每个共享内存段在内核中维护着一个内部结构shmid_ds,

该结构定义在头文件linux/shm.h中,其结构如下:

  1. struct shmid_ds
  2. {
  3. struct ipc_perm shm_perm; //操作许可,里面包含共享内存的用户ID、组ID等信息
  4. int shm_segsz; //共享内存段的大小,单位为字节
  5. __kernel_time_t shm_atime; //最后一个进程访问共享内存的时间
  6. __kernel_time_t shm_dtime; //最后一个进程离开共享内存的时间
  7. __kernel_time_t shm_ctime; //最后一次修改共享内存的时间
  8. __kernel_ipc_pid_t shm_cpid;  //创建共享内存的进程ID
  9. __kernel_ipc_pid_t shm_lpid; //最后操作共享内存的进程ID
  10. ushort shm_nattch; //当前使用该共享内存段的进程数量
  11. ushort shm_unused;
  12. void *shm_unused2;
  13. void *shm_unused3;
  14. };

要获得一个共享内存的描述符,只需提供该共享内存的键值即可,该键值通常由函数ftok返回,该函数原形为:

#include <sys/ipc.h>

key_t ftok(const char *pathname,int proj_id);

创建一个新的共享内存或访问一个已存在的共享内存前需要使用ftok函数得到key值,下面是ftok函数的包裹函数:

  1. key_t Ftok(const char *pathname,int proj_id)
  2. {
  3. key_t key= ftok(pathname,proj_id);
  4. if(key== -)
  5. {
  6. perror("ftok.");
  7. exit();
  8. }
  9. return key;
  10. }

共享内存的创建或打开:

Linux下使用shmget函数来创建一个共享内存区,或者访问已经存在的共享内存区。该函数定义在头文件<sys/shm.h>

中,该函数原形为:

#include <sys/ipc.h>
   #include <sys/msg.h>
   int shmget(key_t key,size_t size,int shmflg);

函数中,第一个参数是由ftok()函数得到的键值,第二个参数size为以字节为单位指定内存的大小,第三个参数shmflg为

操作标志位,它的值为一些宏,如下所示:

  • IPC_CREAT:调用shmget时,系统将此值与其它所有共享内存区的key值进行比较,如果存在相同的key,说明共享内

存区已存在,此时返回该共享内存区的标识符,否则新建一个共享内存区并返回其标识符。

  • IPC_EXCL:该宏必须和IPC_CREAT一起使用,否则没有意义。当shmget取IPC_CREAT|IPC_EXCL时,表示如果发现信号

集已经存在,则返回-1,错误码为EEXIST。

共享内存区的操作:

在使用共享内存区前,必须通过shmat函数将其附加到进程的地址空间。进程与共享内存就建立了连接。shmat调用成

功后就会返回一个指向共享内存区的指针,使用该指针就可以访问共享内存区了,如果失败返回-1。该函数声明在头文件

<sys/shm.h>中,该函数原形为:

#include <sys/types.h>
   #include <sys/shm.h>
   void* shmat(int shmid,const void *shmaddr,int shmflg);

函数中参数shmid为shmget函数的返回值,参数shmaddr为共享内存的附加点,参数shmflg为存取权限标志,参数shmaddr

不同取值情况的含义说明如下:

  • 如果为空,则由内核选择一个空闲的内存区;如果非空,返回地址取决于调用者是否给shmflg参数指定了SHM_RND值,

如果没有指定,则共享内存区附加到由shmaddr指定的地址;否则附加地址为shmaddr向下舍入一个共享内存低端边界地址

后地址(SHMLBA,一个常址)。

  • 通常将参数shmaddr设置为NULL。

当进程结束使用共享内存区时,要通过函数shmdt断开与共享内存区的连接。该函数声明在<sys/shm.h>头文件中,该

函数原形为:

#include <sys/types.h>
   #include <sys/shm.h>
   int shmdt(const void *shmaddr);

参数shmaddr为shmat函数的返回值。该函数调用成功后,返回0,否则返回-1。进程脱离共享内存区后,数据结构shmid_ds

中的shm_nattch就会减1。但是共享内存段依然存在,只有shm_nattch为0后,即没有任何进程再使用共享内存区,共享内存

区才在内核中被删除。一般来说,当一个进程终止时,它所附加的共享内存区都会自动脱离。

共享内存区的控制:

对共享内存区的控制是通过函数shmctl来完成的,该函数定义在<sys/shm.h>中,该函数原形为:

#include <sys/ipc.h>

#include <sys/shm.h>

int shmctl(int shmid,int cmd,struct shmid_ds *buf);

函数中,参数shmid为共享内存区的标识符;参数buf为指向shmid_ds结构体的指针;cmd为操作标志位,支持以下控制操作:

  • IPC_RMID:从系统中删除由shmid标识的共享内存区。
  • IPC_SET:设置共享内存区的shmid_ds结构。
  • IPC_STAT:读取共享内存区的shmid_ds结构,并将其存储到buf指向的地址中。

下面是使用共享内存区发送消息的例子:

  1. // myipc.h
  2. #pragma once
  3.  
  4. #include <stdio.h>
  5. #include <unistd.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <sys/ipc.h>
  9. #include <sys/sem.h>
  10. #include <sys/shm.h>
  11. #include <sys/msg.h>
  12.  
  13. union semun
  14. {
  15. int val;
  16. struct semid_ds *buf;
  17. unsigned short *array;
  18. struct seminfo *__buf;
  19. };
  20.  
  21. key_t Ftok(const char *pathname,int proj_id)
  22. {
  23. key_t key= ftok(pathname,proj_id);
  24. if(key== -)
  25. {
  26. perror("ftok.");
  27. exit();
  28. }
  29. return key;
  30. }
  1. //server.c
  2. #include "myipc.h"
  3.  
  4. int main(int argc,char *argv[])
  5. {
  6. key_t shm_key= Ftok(argv[],atoi(argv[]));
  7. int shm_id= shmget(shm_key,,IPC_CREAT|);
  8. if(shm_id== -)
  9. {
  10. perror("shmget");
  11. exit();
  12. }
  13. char *addr= (char*)shmat(shm_id,NULL,);
  14. if((void*)addr== (void*)-)
  15. {
  16. perror("shmat");
  17. shmctl(shm_id,IPC_RMID,NULL);
  18. exit();
  19. }
  20. key_t sem_key= shm_key;
  21. int sem_id= semget(sem_key,,IPC_CREAT|);
  22. struct sembuf p= {,-,};
  23. struct sembuf v= {,,};
  24. while()
  25. {
  26. printf("Ser: ");
  27. scanf("%s",addr);
  28. semop(sem_id,&v,);
  29.  
  30. semop(sem_id,&p,);
  31. printf("Cli: %s\n",addr);
  32. }
  33. shmdt(addr);
  34. semctl(sem_id,,IPC_RMID);
  35. semctl(sem_id,,IPC_RMID);
  36. shmctl(shm_id,IPC_RMID,NULL);
  37. return ;
  38. }
  1. //client.c
  2. #include "myipc.h"
  3.  
  4. int main(int argc,char *argv[])
  5. {
  6. key_t shm_key= Ftok(argv[],atoi(argv[]));
  7. int shm_id= shmget(shm_key,,);
  8. char *addr= (char*)shmat(shm_id,NULL,);
  9. key_t sem_key= shm_key;
  10. int sem_id= semget(sem_key,,);
  11. struct sembuf p= {,-,};
  12. struct sembuf v= {,,};
  13. while()
  14. {
  15. semop(sem_id,&p,);
  16. printf("Ser: %s\n",addr);
  17. printf("Cli: ");
  18. scanf("%s",addr);
  19. semop(sem_id,&v,);
  20. }
  21. shmdt(addr);
  22. return ;
  23. }

IPC进程间通信---共享内存的更多相关文章

  1. 进程间通信IPC之--共享内存

    每个进程各自有不同的用户地址空间,任何一个进 程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲 区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲 ...

  2. Linux进程间通信—共享内存

    五.共享内存(shared memory) 共享内存映射为一段可以被其他进程访问的内存.该共享内存由一个进程所创建,然后其他进程可以挂载到该共享内存中.共享内存是最快的IPC机制,但由于linux本身 ...

  3. Linux环境进程间通信: 共享内存

    Linux环境进程间通信: 共享内存 第一部分 共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式.两个不同进程A.B共享内存的意思是,同一块物理内存被映射到进程A.B各自的进程地址空间.进 ...

  4. Linux IPC之共享内存C 事例

    Linux IPC之共享内存 标签: linuxrandomnull工作 2011-08-25 11:52 4123人阅读 评论(0) 收藏 举报  分类: Linux(3)  读书札记(3)  版权 ...

  5. C# 进程间通信(共享内存)

    原文:C# 进程间通信(共享内存) 进程间通信的方式有很多,常用的方式有: 1.共享内存(内存映射文件,共享内存DLL). 2.命名管道和匿名管道. 3.发送消息 本文是记录共享内存的方式进行进程间通 ...

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

        共享内存是三个IPC机制中的一个.它允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在进行的进程之间传递数据的一种非常有效的方式.   大多数的共享内存的实现,都把由不同进程之间共享 ...

  7. 【Linux 应用编程】进程管理 - 进程间通信IPC之共享内存 mmap

    IPC(InterProcess Communication,进程间通信)是进程中的重要概念.Linux 进程之间常用的通信方式有: 文件:简单,低效,需要代码控制同步 管道:使用简单,默认阻塞 匿名 ...

  8. 五十、进程间通信——System V IPC 之共享内存

    50.1 共享内存 50.1.1 共享内存的概念 共享内存区域是被多个进程共享的一部分物理内存 多个进程都可把该共享内存映射到自己的虚拟内存空间.所有用户空间的进程若要操作共享内存,都要将其映射到自己 ...

  9. System V IPC 之共享内存

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

随机推荐

  1. Java Jsp使用

    1.Jsp基础 1)Jsp的执行过程 tomcat服务器完成:jsp文件->翻译成java文件->编译成class字节码文件-> 构造类对象-> 调用方法 tomcat的wor ...

  2. 【Machine Learning】决策树之简介(1)

    Content 1.decision tree representation 2.ID3:a top down learning algorithm 3.expressiveness of data ...

  3. 什么是shell? bash和shell有什么关系?

    什么是Shell?      shell是你(用户)和Linux(或者更准确的说,是你和Linux内核)之间的接口程序.你在提示符下输入的每个命令都由shell先解释然后传给Linux内核.      ...

  4. 用两个栈实现队列(C++ 和 Python 实现)

    (说明:本博客中的题目.题目详细说明及参考代码均摘自 “何海涛<剑指Offer:名企面试官精讲典型编程题>2012年”) 题目 用两个栈实现一个队列.队列的声明如下,请实现它的两个函数 a ...

  5. javascript面向对象的写法02

    面向对象特性的初步实现 1.封装 利用作用域封装变量 作用域的概念是一样的,for语句,if语句等这些作用域内定义的变量只能作用域内访问,函数内定义的变量只能函数内访问. function Class ...

  6. less 学习

    收藏地址 : http://www.bootcss.com/p/lesscss/

  7. 《SQL必知必会》总结

    目录   第1章 了解SQL 第2章 检索数据 第3章 排序检索数据 第4章 过滤数据 第5章 高级数据过滤 第6章 用通配符进行过滤 第7章 创建计算字段 第8章 使用数据处理函数 第9章 汇总数据 ...

  8. SAP S/4HANA里如何创建Customer主数据以及执行后续处理

    来自Jerry的同事Zhang Sean. 1, Launch tcode: BP and select the Organization 2, Maintain the information fo ...

  9. mysql 查询大量数据报错

    错误:Incorrect key file for table '/tmp/#sql_... 由于一次查询出大量数据,并且使用了临时表,导致产生此错误,主要是存放临时表文件的/tmp目录大小不足导致.

  10. LRU缓存算法与pylru

    这篇写的略为纠结,算法原理.库都是现成的,我就调用了几个函数而已,这有啥好写的?不过想了想,还是可以介绍一下LRU算法的原理及简单的用法.   LRU(Least Recently Used,最近最少 ...