【linux高级程序设计】(第十一章)System V进程间通信 4
共享内存
共享内存主要用于实现进程间大量数据传输。
共享内存的数据结构定义:
系统对共享内存的限制:
共享内存与管道的对比:
可以看到,共享内存的优势:
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相关推荐
- 《Linux 高级程序设计(第三版)》——导读
** 前言 ** Linux应用开发是目前最为广泛的软件开发内容之一,同时也是从事Linux内核及驱动开发的基础.<Linux高级程序设计>一书经过两次出版,收到了大量的读者来信,对本书提 ...
- linux进程的高级管理,Linux高级程序设计(第2版) PDF扫描版[94MB]
Linux高级程序设计(第2版)以Linux操作系统(内核为2.6版本)为开发平台.GCC 4.0/GDB 6.3为开发调试环境,详细介绍了Linux系统下编程环境及编程工具.文件管理(文件类型.AN ...
- Linux内存管理第十一章 -- Swap Management
文章目录 Linux内存管理第十一章 -- Swap Management Describing the Swap Area Mapping Page Table Entries to Swap En ...
- 深入linux内核架构--第五章 锁与进程间通信
内容简介:主要讲解了Linux各个独立进程间(或线程间)相互通信的机制(主要是System V机制),由于涉及到进程间资源共享,引入资源保护问题,也就是Linux的锁. 5.1 控制机制 首先通过一个 ...
- 【linux高级程序设计】(第十一章)System V进程间通信 1
System V, 曾经也被称为 AT&T System V,是Unix操作系统众多版本中的一支. 传统上,System V 被看作是两种UNIX"风味"之一(另一个是 B ...
- 【Linux命令】《鸟哥Linux基础》第二十一章 软件安装:源代码与Tarball
第二十一章 软件安装:源代码与Tarball 了解:如何将开放源码的程序设计.加入函数库的原理.通过编译而成为可执行的二进制程序,最后该文件可被我们所使用的一连串过程. 这一章介绍最原始的软件管理方式 ...
- 【正点原子Linux连载】第十一章 网络编程 摘自【正点原子】I.MX6U嵌入式Qt开发指南V1.0.2
1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...
- 攻下《JavaScript高级程序设计》——第二章 在HTML中使用JavaScript
从上一章我们知道了,JavaScript是一种专门为网页交互而设计的脚本语言,那么,它就免不了和HTML打交道,所以在设计JavaScript的时候,Netscape首要面临的就是,怎么让HTML和J ...
- 细说linux IPC(十):system V 消息队列
[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] system V消息队列和posix消息队列类 ...
- 【linux高级程序设计】(第十一章)System V进程间通信 3
信号量通信机制 可以看到,跟消息队列类似,也是包括两个结构. int semget (key_t __key, int __nsems, int __semflg) : 创建信号量集合 第一个参数:f ...
最新文章
- 【LeetCode】0830.较大分组的位置
- 无人机飞控开发平台培训理论课程——飞行原理
- Filecoin网络目前总质押量约为2294万枚FIL
- ubuntu proxy
- Oracle存储过程异常
- 测试测量(3)- 如何选择设备的平台
- 乐播投屏显示服务器错误是什么意思,乐播投屏怎么用 乐播投屏常见问题汇总分享...
- 弹性力学经典解法与有限元法的不同特点
- office转换pdf [doc,docx,xls,xlsx]
- 在线Spirte图定位工具,自动生成CSS
- Android仿淘宝头条垂直滚动,垂直走马灯,公告
- uniapp之APP开发
- osgEarth编译——以VS2012为例
- 大数据开发工程师要求高么?有前景么
- 隐藏的Word快捷键操作
- python列表过滤的方法
- 建设工程法规专科【2】
- Bursuite暴力破解实践
- vue获取服务器路径图片显示,vue img图片路径和背景图片路径打包问题
- python实现局域网攻击_牛逼了!一行Python代码搭建一个局域网服务器