共享内存

共享内存主要用于实现进程间大量数据传输。

共享内存的数据结构定义:

系统对共享内存的限制:

共享内存与管道的对比:

可以看到,共享内存的优势:

1.共享内存只需复制2次,而管道需要4次

2.共享内存不需要切换内核态与用户态,而管道需要。

共享内存效率高!

int shmget (key_t __key, size_t __size, int __shmflg) :创建共享内存

第一个参数:key值

第二个参数:欲创建的共享内存段的大小(字节)

第三个参数:shmflg创建标识,包括IPC_CREAT, IPC_EXCL, IPC_NOWAIT, SHM_R(可读), SHM_W(可写)

int shmctl (int __shmid, int __cmd, struct shmid_ds *__buf) :共享内存控制

第一个参数:要操作的共享内存标识符

第二个参数:要执行的操作,IPC_RMID, iPC_SET, IPC_STAT, IPC_INFO, 超级用户还有 SHM_LOCK(锁定共享内存段), SHM_UNLOCK(解锁共享内存段)

第三个参数:临时共享内存变量信息

void *shmat (int __shmid, __const void * __shmaddr, int __shmflg) : 挂载共享内存到当前进程,返回共享内存首地址

第一个参数:要操作的共享内存标识符

第二个参数:指定共享内存映射地址,如果是0,系统选择。

第三个参数:指定共享内存段的访问权限和映射条件,0表示可读可写

int shmdt (__const void *__shmaddr) :把共享内存与当前进程分离,参数为共享内存映射地址

测试,在只读共享内存中写信息:

#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<errno.h>int main(int argc, char * argv[])
{key_t key;int shm_id;char *ptr;key = ftok("/", 10);shm_id = shmget(key, 100, IPC_CREAT|SHM_R); //创建shmprintf("get the shm id is %d\n", shm_id);  //打印idif((ptr = (char *)shmat(shm_id, NULL, SHM_RDONLY)) == NULL)  //只读方式挂载
    {if(shmctl(shm_id, IPC_RMID, NULL) == -1)  //如果失败则删除perror("Failed to remove memory segment");exit(EXIT_FAILURE);}//打印挂载地址printf("the attach add is %p\n", ptr);printf("now try to write the memory\n");*ptr = 'd';printf("*ptr =%c\n", *ptr);shmdt(ptr);shmctl(shm_id, IPC_RMID, 0);
}

发生段错误:

父子进程间对共享内存的约定:

  • fork()的子进程继承父进程挂载的共享内存。
  • 调用exec执行新程序,则共享内存被自动卸载。
  • 如果调用了exit(),挂载的共享内存与当前进程脱离关系。

下面是一个应用的例子

实现两个没有亲缘关系进程的通信,一个负责写,另一个负责接收。用信号量实现同步,即写的时候不可读,读的时候不可写。用一元信号量实现,0表示可写,1表示可读

注意:在代码实现中,实际上是读写轮流操作的,即写一次,读一次。并没有达到真正多进程的效果。

代码经验证,可以使用

发送端代码:

#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/sem.h>
#include<errno.h>int main(int argc, char *argv[])
{int running = 1;int shid;int semid;int value;void *sharem = NULL;struct sembuf sem_b;sem_b.sem_num = 0;sem_b.sem_flg = SEM_UNDO;//创建信号量if((semid = semget((key_t)123456, 1, 0666|IPC_CREAT)) == -1) {perror("semget");exit(EXIT_FAILURE);}//初始化信号量为0if(semctl(semid,0,SETVAL,0) == -1){printf("sem init error");if(semctl(semid, 0, IPC_RMID, 0) != 0){perror("semctl");exit(EXIT_FAILURE);}exit(EXIT_FAILURE);}//创建共享内存shid = shmget((key_t)654321, (size_t)2048, 0600|IPC_CREAT);  //创建共享内存if(shid == -1){perror("shmget");exit(EXIT_FAILURE);}//挂载共享内存到当前进程sharem = shmat(shid, NULL, 0);if(sharem == NULL){perror("shmat");exit(EXIT_FAILURE);}while(running){//测试信号量值,如果为0则可写if((value = semctl(semid, 0, GETVAL)) == 0){printf("write data operate\n");printf("please input something:");scanf("%s", sharem);sem_b.sem_op = 1;//执行信号量加1操作,允许读if(semop(semid, &sem_b, 1) == -1){fprintf(stderr, "semaphore_p failed\n");exit(EXIT_FAILURE);}}//比较是否是结束符号if(strcmp(sharem, "end") == 0)running--;}shmdt(sharem);return 0;
}

接收端代码:

#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/sem.h>
#include<errno.h>int main(int argc, char *argv[])
{int running = 1;int shid;int semid;int value;void *sharem = NULL;struct sembuf sem_b;sem_b.sem_num = 0;sem_b.sem_flg = SEM_UNDO;//创建信号量if((semid = semget((key_t)123456, 1, 0666|IPC_CREAT)) == -1) {perror("semget");exit(EXIT_FAILURE);}//创建共享内存shid = shmget((key_t)654321, (size_t)2048, 0600|IPC_CREAT);  //创建共享内存if(shid == -1){perror("shmget");exit(EXIT_FAILURE);}//挂载共享内存到当前进程sharem = shmat(shid, NULL, 0);if(sharem == NULL){perror("shmat");exit(EXIT_FAILURE);}while(running){//测试信号量值,如果为1则可读if((value = semctl(semid, 0, GETVAL)) == 1){printf("read data operate\n");sem_b.sem_op = -1;//执行信号量减1操作,允许写if(semop(semid, &sem_b, 1) == -1){fprintf(stderr, "semaphore_p failed\n");exit(EXIT_FAILURE);}printf("%s\n", sharem);}//比较是否是结束符号if(strcmp(sharem, "end") == 0)running--;}shmdt(sharem);//删除共享内存if(shmctl(shid, IPC_RMID, 0) != 0){perror("shmctl");exit(EXIT_FAILURE);}//删除信号量if(semctl(semid, 0, IPC_RMID, 0) != 0){perror("semctl");exit(EXIT_FAILURE);}return 0;
}

【linux高级程序设计】(第十一章)System V进程间通信 4相关推荐

  1. 《Linux 高级程序设计(第三版)》——导读

    ** 前言 ** Linux应用开发是目前最为广泛的软件开发内容之一,同时也是从事Linux内核及驱动开发的基础.<Linux高级程序设计>一书经过两次出版,收到了大量的读者来信,对本书提 ...

  2. linux进程的高级管理,Linux高级程序设计(第2版) PDF扫描版[94MB]

    Linux高级程序设计(第2版)以Linux操作系统(内核为2.6版本)为开发平台.GCC 4.0/GDB 6.3为开发调试环境,详细介绍了Linux系统下编程环境及编程工具.文件管理(文件类型.AN ...

  3. Linux内存管理第十一章 -- Swap Management

    文章目录 Linux内存管理第十一章 -- Swap Management Describing the Swap Area Mapping Page Table Entries to Swap En ...

  4. 深入linux内核架构--第五章 锁与进程间通信

    内容简介:主要讲解了Linux各个独立进程间(或线程间)相互通信的机制(主要是System V机制),由于涉及到进程间资源共享,引入资源保护问题,也就是Linux的锁. 5.1 控制机制 首先通过一个 ...

  5. 【linux高级程序设计】(第十一章)System V进程间通信 1

    System V, 曾经也被称为 AT&T System V,是Unix操作系统众多版本中的一支. 传统上,System V 被看作是两种UNIX"风味"之一(另一个是 B ...

  6. 【Linux命令】《鸟哥Linux基础》第二十一章 软件安装:源代码与Tarball

    第二十一章 软件安装:源代码与Tarball 了解:如何将开放源码的程序设计.加入函数库的原理.通过编译而成为可执行的二进制程序,最后该文件可被我们所使用的一连串过程. 这一章介绍最原始的软件管理方式 ...

  7. 【正点原子Linux连载】第十一章 网络编程 摘自【正点原子】I.MX6U嵌入式Qt开发指南V1.0.2

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  8. 攻下《JavaScript高级程序设计》——第二章 在HTML中使用JavaScript

    从上一章我们知道了,JavaScript是一种专门为网页交互而设计的脚本语言,那么,它就免不了和HTML打交道,所以在设计JavaScript的时候,Netscape首要面临的就是,怎么让HTML和J ...

  9. 细说linux IPC(十):system V 消息队列

    [版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] system V消息队列和posix消息队列类 ...

  10. 【linux高级程序设计】(第十一章)System V进程间通信 3

    信号量通信机制 可以看到,跟消息队列类似,也是包括两个结构. int semget (key_t __key, int __nsems, int __semflg) : 创建信号量集合 第一个参数:f ...

最新文章

  1. 【LeetCode】0830.较大分组的位置
  2. 无人机飞控开发平台培训理论课程——飞行原理
  3. Filecoin网络目前总质押量约为2294万枚FIL
  4. ubuntu proxy
  5. Oracle存储过程异常
  6. 测试测量(3)- 如何选择设备的平台
  7. 乐播投屏显示服务器错误是什么意思,乐播投屏怎么用 乐播投屏常见问题汇总分享...
  8. 弹性力学经典解法与有限元法的不同特点
  9. office转换pdf [doc,docx,xls,xlsx]
  10. 在线Spirte图定位工具,自动生成CSS
  11. Android仿淘宝头条垂直滚动,垂直走马灯,公告
  12. uniapp之APP开发
  13. osgEarth编译——以VS2012为例
  14. 大数据开发工程师要求高么?有前景么
  15. 隐藏的Word快捷键操作
  16. python列表过滤的方法
  17. 建设工程法规专科【2】
  18. Bursuite暴力破解实践
  19. vue获取服务器路径图片显示,vue img图片路径和背景图片路径打包问题
  20. python实现局域网攻击_牛逼了!一行Python代码搭建一个局域网服务器

热门文章

  1. EasyUI-增删改操作
  2. jQuery Form Plugin (二) :使用AJAX提交Form表单
  3. com scripting读书笔记
  4. Mac:VMware 虚拟机 连接手机
  5. HDU 2602 Bone Collector 0/1背包
  6. linux常用命令详解(二)
  7. 变量和算术运算之变量(三)
  8. silverlight异常
  9. DispatchAction和MappingDispatchAction区别
  10. 躁动不安的年代,你需要读几本好书(python爬虫及数据分析)