当前位置: 首页 > 编程日记 > 正文

linux进程间通信:POSIX 共享内存

文章目录

        • 思维导图
        • 通信原理
        • 优势
        • POSIX 共享内存 编程接口
        • 编程案例

思维导图

在这里插入图片描述
之前学习过sysemV 的共享内存的实现及使用原理,参考linux进程间通信:system V 共享内存
POSIX 同样提供共享内存的接口,基本原理和system V的共享内存是一样的。

通信原理

  • 多个进程共享物理内存的同一块区域(通常称之为“段”:segment)
  • 抛弃了内核态消息转存处理的过程,让两个进程直接通过一块内存进行通信

我们普通的像PIPE,FIFO,消息队列等的通信方式如下图:
在这里插入图片描述
这种方式的通信不论读写,都需要内核态(系统调用 read,write,pipe,mkfifo,msgget,msgsnd,msgrcv等)的介入,而且都需要经过数据从虚拟地址空间到物理地址空间的拷贝。
而共享内存的通信方式则都避免了以上的通信问题,直接为两个进程开辟相同的内存空间进行数据交互。
在这里插入图片描述

优势

  • 减少了内存的拷贝(从用户拷贝到内核,从内核拷贝到用户)
  • 减少了2次系统调用(系统调用比较消耗性能,因为CPU处理系统调用时需要从用户态切换到内核态),提高了系统性能

POSIX 共享内存 编程接口

关于共享内存的接口详细使用就不一一描述,可以通过man shm_open这种类似的方式查看具体如何使用接口

//创建共享内存
int shm_open(const char *name, int oflag, mode_t mode);
//当共享内存引用计数为0时,删除共享内存
int shm_unlink(const char *name);
//获取文件相关的信息,将获取到的信息放入到statbuf结构体中
int fstat(int fd, struct stat *statbuf);
//调整文件大小,通过裁剪指定字节达到对文件大小的精准控制
int ftruncate(int fd, off_t length);
//将进程空间的文件映射到内存,也可以将进程空间的匿名区域映射到内存
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
//解除文件或者匿名映射
int munmap(void *addr, size_t length);

以上接口包含头文件 <sys/mman.h> <sys/mman.h>

编程案例

  1. 共享内存基本使用
    shm_read.c 共享内存的读端

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <string.h>
    #include <fcntl.h>#define SHM_NAME "/shm"int main() {int shm_fd;//创建共享内存文件标识符shm_fd = shm_open(SHM_NAME, O_RDWR | O_CREAT, 0666);if (shm_fd == -1) {printf("shm_open failed\n");}//设置共享内存的文件大小ftruncate(shm_fd , 8192);//获取共享内存文件相关属性信息,这里获取的是文件大小struct stat filestat;fstat(shm_fd, &filestat);printf("st_size :%ld\n",filestat.st_size);//映射共享内存,并获取共享内存的地址char *shm_ptr;shm_ptr = (char*)mmap(NULL,filestat.st_size,\PROT_READ|PROT_WRITE,MAP_SHARED,shm_fd,0);close(shm_fd);//获取共享内存地址中的内容并打印,最后再解除映射,删除共享内存printf("pid %d:%s\n",getpid(),shm_ptr);munmap(shm_ptr, filestat.st_size);shm_unlink(SHM_NAME);return 0;
    }
    

    shm_write.c共享内存的写端

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <string.h>
    #include <fcntl.h>#define SHM_NAME "/shm"int main() {int shm_fd;//创建和读端相同的文件标识shm_fd = shm_open(SHM_NAME, O_RDWR | O_CREAT, 0666);if (shm_fd == -1) {printf("shm_open failed\n");}ftruncate(shm_fd , 8192);struct stat filestat;fstat(shm_fd, &filestat);printf("st_size :%ld\n",filestat.st_size);char *shm_ptr;shm_ptr = (char*)mmap(NULL,filestat.st_size,\PROT_READ|PROT_WRITE,MAP_SHARED,shm_fd,0);close(shm_fd);//向共享内存中写入数据,这里利用memmove进行内存拷贝写入char buf[] = "hello world";memmove(shm_ptr,buf,sizeof(buf));printf("pid %d:%s\n",getpid(),shm_ptr);//写入完成后解除映射munmap(shm_ptr, filestat.st_size);return 0;
    }
    

    编译gcc shm_read.c -o read -lrt gcc shm_write.c -o write -lrt
    输出如下:
    在这里插入图片描述

  2. 共享内存和信号量一同使用,内存访问的同步
    当读端能够读出的前提是读的时候信号量的value值为1,否则无法读出
    同样写的时候对信号量进行v操作,将信号量的value值加1,为读提供同步条件

    实现如下
    读端sem_shm_read.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <semaphore.h>
    #include <string.h>
    #include <fcntl.h>#define SHM_NAME "/shm"
    #define SEM_NAME "/memmap_sem"int main() {//增加信号量的初始创建int shm_fd;sem_t *sem;shm_fd = shm_open(SHM_NAME, O_RDWR | O_CREAT, 0666);sem = sem_open(SEM_NAME, O_CREAT, 0666, 0);if (shm_fd == -1 || sem == SEM_FAILED) {printf("open failed\n");_exit(-1);}ftruncate(shm_fd , 8192);struct stat filestat;fstat(shm_fd, &filestat);printf("st_size :%ld\n",filestat.st_size);char *shm_ptr;shm_ptr = (char*)mmap(NULL,filestat.st_size,\PROT_READ|PROT_WRITE,MAP_SHARED,shm_fd,0);close(shm_fd);//读的时候对信号量做p操作(-1),如果信号量此时为0时则无法读出sem_wait(sem);printf("pid %d:%s\n",getpid(),shm_ptr);sem_close(sem);//读完之后删除共享内存,删除信号量munmap(shm_ptr, filestat.st_size);shm_unlink(SHM_NAME);sem_unlink(SEM_NAME);return 0;
    }
    

    写端shm_write.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <semaphore.h>
    #include <string.h>
    #include <fcntl.h>#define SHM_NAME "/shm"
    #define SEM_NAME "/memmap_sem"int main() {int shm_fd;sem_t *sem;shm_fd = shm_open(SHM_NAME, O_RDWR | O_CREAT, 0666);sem = sem_open(SEM_NAME, O_CREAT, 0666, 0);if (shm_fd == -1 || sem == SEM_FAILED) {printf("open failed\n");_exit(-1);}ftruncate(shm_fd , 8192);struct stat filestat;fstat(shm_fd, &filestat);printf("st_size :%ld\n",filestat.st_size);char *shm_ptr;shm_ptr = (char*)mmap(NULL,filestat.st_size,\PROT_READ|PROT_WRITE,MAP_SHARED,shm_fd,0);close(shm_fd);char buf[] = "hello world";memmove(shm_ptr,buf,sizeof(buf));printf("pid %d:%s\n",getpid(),shm_ptr);//写的时候对信号量的值执行v(+1)操作, 方便后续的读sem_post(sem);sem_close(sem);munmap(shm_ptr, filestat.st_size);return 0;
    }
    

相关文章:

求二进制中1的个数(编程之美2.1)

行文脉络 解法一——除法解法二——移位解法三——高效移位解法四——查表扩展问题——异或后转化为该问题对于一个字节&#xff08;8bit&#xff09;的变量&#xff0c;求其二进制“1”的个数。例如6&#xff08;二进制0000 0110&#xff09;“1”的个数为2&#xff0c;要求算…

mysql管理用户数据库_MySQL 数据库管理(一)(用户与受权)

前言在企业信息化的过程当中&#xff0c;数据库中库和表都会大量存在&#xff0c;须要分配给管理者核实的权限进行操做合理地分配权限&#xff0c;可使数据库管理井井有理&#xff0c;各个管理者只须要关注本身负责的内容&#xff0c;也可避免误操做对系统形成损失1、用户与受权…

Smart-linkmonitor-link配置注意事项

一、应用场合 Smart Link用于双上行组网&#xff0c;Monitor Link一般用于与Smart Link的联动&#xff0c;配置在Smart Link的上游设备。 二、注意事项 在配置过程中&#xff0c;请注意以下几点&#xff1a; ? 1、指定实例之前请先配置MSTP实例。MSTP的实例和VLAN映射关系发生…

封装OpenCL类

以上一篇《OpenCL入门测试》为基础&#xff0c;将函数封装到类中&#xff0c;方便调用。 #include <cstdlib> #include <iostream> #include <iomanip> #include <cstring> #include <cassert> #include <windows.h> #define CL_USE_DEPRE…

linux系统调用 ftruncate设置文件大小

系统调用ftruncate可以将一个文件裁剪为指定的大小&#xff0c;函数描述如下&#xff1a; 头文件&#xff1a;<unistd.h> <sys/types.h>函数使用&#xff1a; int truncate(const char *path, off_t length); int ftruncate(int fd, off_t length);函数参数&…

剑指 offer set 22 数组中的逆序数

总结 1. 题目为归并排序的变形, 不过我完全没想到 2. 在归并排序进行字符组 merge 时, 统计逆序数. merge 后, 两个子数组是有序的了, 下次再 merge 的时候就能以 o(n) 的时间内找到某一个逆序对第二个元素的个数 转载于:https://www.cnblogs.com/xinsheng/p/3564026.html

qt信号发送间隔短而槽耗时多_Qt信号槽问题汇总 - osc_9q1dp3jk的个人空间 - OSCHINA - 中文开源技术交流社区...

1. 发送一次信号&#xff0c;调用多次槽函数问题在同一个类中&#xff0c;多次链接QObject::connect(sender, SIGNAL(signalSender(QString, int)), receiver, SLOT(onSignalSender(QString, int))); 会导致发送一次信号signalSender(QString, int) 多次调用槽函数(onSignalSen…

一劳永逸关闭Windwos默认共享

对于IPC$&#xff0c;找到注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\LSA下的RestrictAnonymous项&#xff0c;并将键值改为1。 对于其它默认共享&#xff0c;在注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters下&#…

springboot 集成mybatis时日志输出

application.properties(yml)中配置的两种方式&#xff1a; 这两种方式的效果是一样的&#xff0c;但是下面一种可以指定某个包下的SQL打印出来&#xff0c;上面这个会全部的都会打印出来。 转载于:https://www.cnblogs.com/z0909y/p/10077565.html

linux文件IO与内存映射:用户空间的IO缓冲区

文章目录用户空间IO缓冲区产生IO缓冲区 描述IO缓冲区的写模式自定义IO缓冲区用户空间IO缓冲区产生 系统调用过程中会产生的开销如下&#xff1a; 切换CPU到内核态进行数据内容的拷贝&#xff0c;从用户态到内核态或者从内核态到用户态切换CPU到用户态 以上为普通到系统调用过…

java zookeeper_Java zookeeper开发实例

1、安装zookeeper下载zk http://archive.cloudera.com/cdh5/cdh/5/配置文件tickTime2000initLimit10syncLimit5# zk数据保存目录dataDir/usr/local/zookeeper/dataclientPort2181启动&#xff1a;bin/zkServer.sh start客户端命令行链接&#xff1a;bin/zkCli.sh2、拷贝zookeep…

【转】Maven Jetty 插件的问题(css/js等目录死锁)的解决

Maven Jetty 插件的问题&#xff08;css/js等目录死锁&#xff0c;不能自动刷新&#xff09;的解决&#xff1a;1. 打开下面的目录&#xff1a;C:\Users\用户名\.m2\repository\org\eclipse\jetty\jetty-webapp\&#xff0c;在进入版本对应的子目录&#xff0c;例如8.1.3.v2012…

ORA-4031错误深入解析

报ORA-4031错误时&#xff0c;我们通常可以根据Oracle无法分配多少字节的内存&#xff0c;来判断共享池碎片的严重程度&#xff0c;以下是4031错误官方的解释&#xff1a;[oracleguoyj ~]$ oerr ORA 403104031, 00000, "unable to allocate %s bytes of shared memory (\&…

buffers与cached的区别

具体参考以下博文&#xff1a; 1、https://www.cnblogs.com/chenpingzhao/p/5161844.html 2、https://blog.csdn.net/heweimingming/article/details/52230293 3、http://www.cnblogs.com/zhoug2020/p/6336453.html 其中3有top命令的详解。转载于:https://www.cnblogs.com/jia…

linux文件IO与内存映射:分散/聚集IO技术(scatter-gather)

前言 根据上文我们学习到的用户空间的IO缓冲区&#xff0c;操作系统为了减少系统调用的次数&#xff0c;节省系统开销&#xff0c;提出了用户空间的IO缓冲区&#xff0c;即为用户空间的文件读写开辟一段可以利用setvbuf配置大小的内存空间来作为文件IO缓冲区。 描述 为了在以…

android jni 调用 java_Android与JNI(二) ---- Java调用C++ 动态调用

目录&#xff1a;1. 简介2. JNI 组件的入口函数3. 使用 registerNativeMethods 方法4. 测试5. JNI 帮助方法6. 参考资料1. 简介Android与JNI(一)已经简单介绍了如何在 android 环境下使用 JNI 了。但是遵循 JNI 开发的基本步骤似乎有点死板&#xff0c;而且得到的本地函数名太…

如何查找并干掉僵尸进程

查找命令&#xff1a;ps -A -o stat,pid,ppid,cmd | grep -e ^[Zz] 找到之后 kill掉&#xff0c;然后用top命令查看是否kill成功&#xff0c;如果失败&#xff0c;kill 父进程。 转载于:https://www.cnblogs.com/kfx2007/p/3572249.html

[转] WINCC教学视频

原文地址http://www.ad.siemens.com.cn/club/bbs/post.aspx?b_id5&a_id1049763&s_id17&num0#anch WinCC 变量归档系列视频&#xff1a; http://www.ad.siemens.com.cn/service/elearning/cn/SerialVideo.aspx?vsid136 WinCC亚洲版高级工程师培训视频&#xff1a;…

UNL(Ubiquitous Navigation Lab)

转载于:https://www.cnblogs.com/Forwithy/p/10080078.html

linux 文件IO与内存映射:内存映射

前言 前面几篇我们学习了用户空间的IO缓冲区,以及IO缓冲区的分散聚合IO技术. 为了减少系统调用的次数&#xff0c;提升系统性能&#xff0c;操作系统开发者门提出了这么多的缓存技术。 但是到这里这些技术同样有不足的地方&#xff1a;不论是读或者写文件&#xff0c;都需要将…

Java网页数据采集器[下篇-数据查询]【转载】

本期概述 上一期我们学习了如何将html采集到的数据存储到MySql数据库中,这期我们来学习下如何在存储的数据中查询我们实际想看到的数据. 数据采集页面 2011-2012赛季英超球队战绩 如果是初学者 以下可能对你有帮助 Java如何操作MySql?在使用java 操作MySql数据库之前 我们需要…

loadrunner 调用java_LoadRunner调用Java程序—性能测试

为了充分利用LoadRunner的场景控制和分析器&#xff0c;帮助我们更好地控制脚本加载过程&#xff0c;从而展现更直观有效的场景分析图表。本次将重点讨论LoadRunner如何调用Java测试代码&#xff0c;完成压力测试。通常我们在执行一些Server的压力测试的时候&#xff0c;总会不…

《The Art of Readable Code》 读书笔记 01

放假前在学校图书馆借了一本新书《The Art of Readable Code》&#xff0c;寒假回来看看&#xff0c;写写其中的Key Idea 、summary和一些读书笔记。 Preface 前言部分主要概况讲了本书的核心思想——Code shoule be easy to understand。接着探讨什么是好代码&#xff0c;是内…

吴裕雄 10-MySQL插入数据

语法以下为向MySQL数据表插入数据通用的 INSERT INTO SQL语法&#xff1a;INSERT INTO table_name ( field1, field2,...fieldN ) VALUES ( value1, value2,...valueN );如果数据是字符型&#xff0c;必须使用单引号或者双引号&#xff0c;如&#xff1a;"value"。 通…

编译内核指定模块,筛选当前模块依赖的组件

关于内核模块编译的过程中&#xff0c;往往我们仅仅需要其中一个小的模块&#xff0c;但是却因为内核源码的庞杂而止步与模块依赖的筛选过程中。 为了更加便捷得对内核各个模块进行管理&#xff0c;这里提供一个小脚本来进行指定模块相关得模块留存&#xff0c;不相关的模块代码…

计算机启动和操作系统加载小话

整个启动和加载过程可分为若干步骤&#xff0c;或者称为若干个状态&#xff0c;或者快照&#xff0c;下面的每一段都是描述一个快照。&#xff08;类似自动状态机&#xff09; 1、电源稳定&#xff08;POWER GOOD&#xff09; 按下启动键后&#xff0c;电源首先启动。为了保证安…

java清空栈_java - 如何使用Intent.FLAG_ACTIVITY_CLEAR_TOP清除活动堆栈?

java - 如何使用Intent.FLAG_ACTIVITY_CLEAR_TOP清除活动堆栈&#xff1f;我已经阅读了几篇关于使用它的帖子&#xff0c;但必须遗漏一些因为它不适合我。 我的活动A在清单中有launchmode “singleTop”。 它启动活动B&#xff0c;启动模式“singleInstance”。 活动B打开浏览器…

「学习笔记-Linux」学习Shell Script

学习Shell Script Table of Contents 1 什么是Shell Scipt 1.1 程序书写1.2 程序执行2 简单Shell练习 2.1 例1 接收用户输入2.2 例2 按日期建立相似名字的文件3 判断式 3.1 测试文件是否存在3.2 test常用选项 3.2.1 文件类型3.2.2 权限3.2.3 文件新旧比较3.2.4 整数&#xff0c…

django admin组件

admin实例 from django.contrib import admin from app01 import models from django.utils.safestring import mark_safe # Register your models here. class UserInfoConfig(admin.ModelAdmin):# 自定义显示的东西def xxx(self):return mark_safe(<a href>xx</a>…

C语言网络编程:close或者shutdown断开通信连接

文章目录前言close函数介绍shutdown函数介绍前言 这里在主要通过实例进行描述close函数在网络编程中的使用 TCP编程模型中客户端或者服务器只要主动通过close发起断开连接的请求&#xff0c;则通信连接可以中断。 可以通过在主进程中抓取通信端的断开信号&#xff0c;比如SIGI…