【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("/", );
shm_id = shmget(key, , IPC_CREAT|SHM_R); //创建shm
printf("get the shm id is %d\n", shm_id); //打印id
if((ptr = (char *)shmat(shm_id, NULL, SHM_RDONLY)) == NULL) //只读方式挂载
{
if(shmctl(shm_id, IPC_RMID, NULL) == -) //如果失败则删除
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, );
}
发生段错误:
父子进程间对共享内存的约定:
- 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 = ;
int shid;
int semid;
int value;
void *sharem = NULL;
struct sembuf sem_b;
sem_b.sem_num = ;
sem_b.sem_flg = SEM_UNDO;
//创建信号量
if((semid = semget((key_t), , |IPC_CREAT)) == -)
{
perror("semget");
exit(EXIT_FAILURE);
}
//初始化信号量为0
if(semctl(semid,,SETVAL,) == -)
{
printf("sem init error");
if(semctl(semid, , IPC_RMID, ) != )
{
perror("semctl");
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
}
//创建共享内存
shid = shmget((key_t), (size_t), |IPC_CREAT); //创建共享内存
if(shid == -)
{
perror("shmget");
exit(EXIT_FAILURE);
}
//挂载共享内存到当前进程
sharem = shmat(shid, NULL, );
if(sharem == NULL)
{
perror("shmat");
exit(EXIT_FAILURE);
}
while(running)
{
//测试信号量值,如果为0则可写
if((value = semctl(semid, , GETVAL)) == )
{
printf("write data operate\n");
printf("please input something:");
scanf("%s", sharem);
sem_b.sem_op = ;
//执行信号量加1操作,允许读
if(semop(semid, &sem_b, ) == -)
{
fprintf(stderr, "semaphore_p failed\n");
exit(EXIT_FAILURE);
}
}
//比较是否是结束符号
if(strcmp(sharem, "end") == )
running--;
}
shmdt(sharem);
return ;
}
接收端代码:
#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 = ;
int shid;
int semid;
int value;
void *sharem = NULL;
struct sembuf sem_b;
sem_b.sem_num = ;
sem_b.sem_flg = SEM_UNDO;
//创建信号量
if((semid = semget((key_t), , |IPC_CREAT)) == -)
{
perror("semget");
exit(EXIT_FAILURE);
}
//创建共享内存
shid = shmget((key_t), (size_t), |IPC_CREAT); //创建共享内存
if(shid == -)
{
perror("shmget");
exit(EXIT_FAILURE);
}
//挂载共享内存到当前进程
sharem = shmat(shid, NULL, );
if(sharem == NULL)
{
perror("shmat");
exit(EXIT_FAILURE);
}
while(running)
{
//测试信号量值,如果为1则可读
if((value = semctl(semid, , GETVAL)) == )
{
printf("read data operate\n");
sem_b.sem_op = -;
//执行信号量减1操作,允许写
if(semop(semid, &sem_b, ) == -)
{
fprintf(stderr, "semaphore_p failed\n");
exit(EXIT_FAILURE);
}
printf("%s\n", sharem);
}
//比较是否是结束符号
if(strcmp(sharem, "end") == )
running--;
}
shmdt(sharem);
//删除共享内存
if(shmctl(shid, IPC_RMID, ) != )
{
perror("shmctl");
exit(EXIT_FAILURE);
}
//删除信号量
if(semctl(semid, , IPC_RMID, ) != )
{
perror("semctl");
exit(EXIT_FAILURE);
}
return ;
}
【linux高级程序设计】(第十一章)System V进程间通信 4的更多相关文章
- 第三十一章 System V信号量(二)
用信号量实现进程互斥示例 #include <unistd.h> #include <sys/types.h> #include <stdlib.h> #inclu ...
- 读书笔记 - js高级程序设计 - 第十一章 DOM扩展
对DOM的两个主要的扩展 Selectors API HTML5 Element Traversal 元素遍历规范 querySelector var body = document.query ...
- 《JavaScript高级程序设计》——第二章在HTML使用JavaScript
这章讲的是JavaScript在HTML中的使用,也就是<script>元素的属性.书中详细讲了async.defer.src和type四个<script>的属性. 下面是对第 ...
- ipc - System V 进程间通信机制
SYNOPSIS 总览 # include <sys/types.h> # include <sys/ipc.h> # include <sys/msg.h> # ...
- 【linux高级程序设计】(第十一章)System V进程间通信 1
System V, 曾经也被称为 AT&T System V,是Unix操作系统众多版本中的一支. 传统上,System V 被看作是两种UNIX"风味"之一(另一个是 B ...
- Linux进程通信 之 信号灯(semphore)(System V && POSIX)
一. 信号灯简介 信号灯与其他进程间通信方式不大相同,它主要提供对进程间共享资源访问控制机制. 相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时,进程 也可以修改该标志.除了用于访 ...
- 《Unix网络编程》卷2 读书笔记 第3章- System V IPC
1. 概述 三种类型的System V IPC:System V 消息队列.System V 信号量.System V 共享内存区 System V IPC在访问它们的函数和内核为它们维护的信息上共享 ...
- 第11章 System V 信号量
11.1 概述 信号量按功能分:二值信号量.计数信号量.信号量集:其中二值信号量和计数信号量指的是Posix信号量,信号量集指的是System V信号量.
- 第6章 System V消息队列
6.1 概述 System V消息队列在内核中是list存放的,头结点中有2个指针msg_first 和msg_last.其中每个节点包含:下个节点地址的指针.类型.长度.数据等. 6.2 函数 6. ...
- 第3章 System V IPC
3.1 概述 System V IPC 包含:System V消息队列.System V信号量.System V共享内存. 3.2 key_t 键和 ftok函数 这三种类型的System V IPC ...
随机推荐
- linux命令随身记
赋予权限命令:chmod 755 * 查询进程: ps -ef |grep abc 查看含有"abc"的活动进程 ps -ef |grep -v abc 查看不含abc的活动进程 ...
- WPF图片预览之移动、旋转、缩放
原文:WPF图片预览之移动.旋转.缩放 RT,这个功能比较常见,但凡涉及到图片预览的都跑不了,在说自己的实现方式前,介绍一个好用的控件:Extended.Toolkit中的Zoombox,感兴趣的同学 ...
- PaaS服务之路漫谈(一)
此文已由作者尧飘海授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. PaaS服务之路漫谈(一) 1983年,SUN公司提出的网络即计算的理念:2006年亚马逊(Amazon)推 ...
- 云计算之路-阿里云上:OCS问题的进展以及11:30-11:50遇到的问题
(上图是今天出问题期间Web服务器性能监控图,紫色表示的是Request Execution Time) 昨天我们发布了一篇博客分享了我们这两天遇到的OCS(开放缓存服务)问题,详见云计算之路-阿里云 ...
- 《Cracking the Coding Interview》——第14章:Java——题目1
2014-04-26 18:20 题目:从继承的角度,把构造函数设成private有什么意义? 解法:就不能继承了.单体模式里也这么干,目的是为了不让使用者自主生成对象,进行限制. 代码: // 14 ...
- Python作业--登录接口
作业需求: 编写登陆接口 输入用户名密码 认证成功后显示欢迎信息 输错三次后锁定 实现思路: 1.从文件获取用户名密码 2.判断是否在黑名单中 3.验证用户名密码 成功:输出认证成功 错误:判断验证次 ...
- 小红帽安装centos的yum的一些坑!
[root@localhost ~]# lsanaconda-ks.cfg yum-3.4.3-158.el7.centos.noarch.rpm yum-updateonboot-1.1.31-45 ...
- 团队项目-任务分解[Alpha0]
团队项目-任务分解[Alpha0] 标签(空格分隔): 团队博客 适用范围: 本文档 适用对象 团队全体成员 适用时间 alpha阶段第一周计划 10.24-10.28 适用内容 目标.分工.时长估计 ...
- Struts2 学习笔记
1)Strust2是以WebWork为核心,采用拦截器的机制对用户请求进行处理. 2)Struts2框架结构: 3)简单来看整个Struts2的处理过程可以简单的理解为 用户的请求发送给对应的Acti ...
- web自动化测试:watir+minitest(五)
测试报告: 加载minitest-reporters库,并设置相关的参数.既可以在每次运行测试后生成响应的测试报告. 默认会生成一份html的报告在当前目录的test目录下 我们可以指定参数对报告的标 ...