Linux学习之system V

目录

一,system V共享内存

快速认识接口

 shmget(shared memory get)

shmat(shared memory attach)

shmdt(shared memory delete)

 shmctl (shared memory control)

 编写代码

综上那么共享内存与管道通信有什么区别?

system v消息队列

system v信号量


一,system V共享内存

除了管道通信方式,对于操作系统自己本身,操作系统为了内核中的通信单独设计了通信模块。

进程通信的前提:让不同进程看到同一份资源

共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到 内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。

首先我们从shared memory,共享内存开始,所谓的共享内存,本质上就是将同一份资源,通过加载到物理内存,同时映射到两个进程的内存空间,实现资源共享。

此外,在操作系统中一定会允许多个共享内存,此时就需要操作系统来管理这些共享内存。

快速认识接口

 shmget(shared memory get)

创建共享内存 既能创建,又能获取

参数一为创建的key,参数二为空间大小,

参数三为标记位:

 IPC_CREAT   to create a new segment.  If this flag is not used, then shmget() will find the segment associated with key and check to see . if  the user has permission to access the segment.(没有就创建shm(共享内存))

PC_EXCL    used with IPC_CREAT to ensure failure if the segment already exists.(通常与IPC_CREAT结合使用,不存在就创建,存在就出错返回不创建)。

通过这两个标志位使得我们创建的内存是全新的。

shmat(shared memory attach)

将共享内存挂接到地址空间当中

参数一位shmid,参数2一般设置位nullptr,参数三为标志位表示已什么样的方式挂在,一般也用0。

返回值位起始地址。通过引用计数来计算有多少进程挂在到当前共享内存中。

shmdt(shared memory delete)

去掉内存关联,将共享内存从进程地址空间中移除。

 shmctl (shared memory control)

控制共享内存,第一个参数位shmid,第二个位操作指令,IPC_STAT,IPC_SET, IPC_RMID(删除) ,IPC_INFO

 编写代码

和命名管道通信的方式一样,我们创建了三个文件server,client,commant.cpp,用来观察进程通信:

首先对于读端还是写端都会有同一个key,我们创建同一个key,此时进程就会把key写到地址空间当中,通过Key值操作系统可以找到两个进程的同一块地址空间,即key值指向的内存就是共享内存。

comman.hpp

#pragma once
#include<iostream>
#include<string>
#include<cstdlib>
#include<unistd.h>
const std::string pathname="/home/danchengwei/myfile/file7";
const int proj_id=0x11223344;
const int size=4096;
//管道文件
const std::string filename = "fifo";key_t getkey(){//转换pathname为keykey_t key=ftok(pathname.c_str(),proj_id);//convert a pathname and a project identifier to a System V IPC keyif(key<0){std::cerr<<"errno:"<<errno<<",strerror"<<strerror(errno)<<std::endl;return 1;}std::cout<<"key:"<<key<<std::endl;return key;}std::string tohex(int id){char buffer[1024];snprintf(buffer,sizeof(buffer),"0x%x",id);return buffer;}int creatshmHLPER(key_t key,int flag){int shmid=shmget(key,size,flag); //成光返回id,错误返回-1if(shmid<0){std::cerr<<"errno:"<<errno<<",strerror"<<strerror(errno)<<std::endl;exit(2);}std::cout<<"shmid:"<<shmid<<std::endl;return shmid;}int getshm(key_t key){return creatshmHLPER(key,IPC_CREAT | IPC_EXCL | 0644);}int creatshm(key_t key){return creatshmHLPER(key,IPC_CREAT);}bool MakeFifo()
{int n = mkfifo(filename.c_str(), 0666);if(n < 0){std::cerr << "errno: " << errno << ", errstring: " << strerror(errno) << std::endl;return false;}std::cout << "mkfifo success... read" << std::endl;return true;
}

server

#include<iostream>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include"comman.hpp"
using namespace std;int main()
{//创建共享内存key_t key=getkey();//key在应用层我们一般不去使用,我们使用的是shmid int shmid=creatshm(key);sleep(10);//挂载 ,即将共享内存映射到进程的地址空间当中。char*s=(char*)shmat(shmid,nullptr,0);//打开管道Start:int rfd=open(filename.c_str(),O_RDONLY);if(rfd<0){//cerr<<"errno:"<<errno<<",errstring:"<<strerror(errno)<<endl;if(MakeFifo()){goto Start;}else{return 1 ;}//return 2;}cout<<"打开管道成功..."<<endl;char buffer[1024];while(true){ssize_t s=read(rfd,buffer,sizeof(buffer)-1);if(s>0){buffer[s]=0;//表示以/0结尾cout<<"cilent reply: "<<buffer<<endl;}if(s<=0){cout<<"no data had reciveed"<<endl;//没有数据可读了,退出进程break;}}//关闭管道close(rfd);cout<<"关闭管道成功..."<<endl;sleep(5);//在地址空间当中移除共享内存shmdt(s); sleep(5);//按照id删除shmctl(shmid,IPC_RMID,nullptr);sleep(5);return 0;}

创建完成可以通过指令查看共享内存:

ipcs -m  //查看共享内存
ipcrm -m shmid  //删除共享内存

其中natch表示有几个进程挂接到该共享内存。

程序结束,共享内存被创建之后并没有释放。它的生命周期时内核决定的。

之后我们再完成与server一样的client的编写:

#include<iostream>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include"comman.hpp"
using namespace std;int main()
{//与server一样//获取key值key_t key=getkey();//创建共享内存int shmid=creatshm(key);sleep(10);//把共享内存挂载到地址空间当中char *s=(char*)shmat(shmid,nullptr,0);sleep(5);//打开管道int wfd = open(filename.c_str(), O_WRONLY);//数据写入string message;while(true){cout<<"请输入你要发送的数据:"<<endl;getline(cin,message);//这里再写入管道时,我们使用c++string再转化为c字符串ssize_t t=write(wfd,message.c_str(),message.size());if(t<0){cerr<<"错误码:"<<errno<<",错误原因:"<<strerror(errno)<<endl;break;}}//关闭管道close(wfd);cout<<"关闭管道成功..."<<endl;//取消共享内存的挂载shmdt(s);return 0;
}

之后我们就可以同时执行两个进程并观察会发现 ,刚开始创建共享内存,server与client挂载到地址空间,natch增加,之后移除,之后删除.

有了共享内存,那么我们现在通过共享内存就可以实现进程之间的通信,和管道类似,我们可以增加一个管道文件;之后用一端作为读端,一端作为写端。

综上那么共享内存与管道通信有什么区别?

其实共享内存是比管道通信更加快速的,对于共享内存,考虑硬件:

第一次拷贝是从外设到共享内存,第二次是从共享内存写到显示器上,只需要拷贝两次,对于管道.

而对于管道,先是用户到键盘(外设)把数据读到缓冲区中,再把数据拷贝到管道当中(写入),之后再将管道的数据写道别的用户的缓冲区(读),最后再将数据给到显示器(外设)。对于管道考虑硬件需要拷贝四次数据。

system v消息队列

所谓的消息队列是提供让一个进程给另一个进程发送数据块的能力,使用的接口msgctl,使用方法基本和共享内存大致相同。

参数一为msqid即这里的key,参数二为如何去操作消息队列的指令,参数三一般为nullptr.

创建完成之后可以用指令ipcs -q来查看消息对列。根据接口的第二参数我们可以还选择删除消息队列。可以看到使用与共享内存非常的相似。

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include<iostream>
#include"comman.hpp"//消息队列
int main()
{//获取key值key_t key=getkey();//创建消息队列int msgid=msgget(key,IPC_CREAT | IPC_EXCL);std::cout<<"msgid:"<<msgid<<std::endl;sleep(10);//删除消息队列msgctl(msgid,IPC_RMID,nullptr);rteurn 0;
}

其次消息队列也可以存在多个,两个进程用多个消息队列进行数据交互,因此在内核当中,操作系统需要管理这些消息队列,先描述在组织,因此消息队列的管理就是消息队列加自身的属性。

关于消息队列大家感兴趣可以查看手册的使用。

system v信号量

信号量主要用于同步和互斥的,当进程们面对同一份资源时,我们的资源就需要被保护起来,而信号量就是为了保护我们的共享资源。

因此我么先来了解同步与互斥:

进程互斥
程互斥则是一种防止多个进程同时访问同一资源的机制。在进程互斥的机制下,当一个进程正在访问某个共享资源时,其他进程需要等待该进程释放该资源之后才能访问。实现进程互斥的主要方法有互斥锁和信号量。

进程同步

指的是多个进程在共享资源的过程中保持一致性的机制。其主要目的是避免进程间的竞争和冲突,确保多个进程对共享资源的访问按照一定的顺序和规则进行,从而避免资源的竞争和冲突。

进程同步的实现方法包括信号量、互斥锁、条件变量等。
 

对于linux系统就是用洗脑两盒互斥锁来解决同步与互斥的问题。

信号量(semaphore),我们在linux中也有对应的函数接口:

semget 获取创建信号量

semctl 控制信号量

数1为semid,参数二为编号(起始从0开始),参数三为指令。

semop 操作信号量

对信号量做加加减减操作

 

可以看到无论是共享内存,还是消息对列或者信号量,他们都是有统一的标准的接口,因此这里的函数我们也能使用了。

返回值一般我们叫做semid,参数一为key值,参数二为创建的个数,参数三为标志.

利用指令ipcs -s 可以查看创建的信号量,可以看到创建完进程结束,但信号量还在,因此生命周期还是随内核。

当然对于信号量,也是需要被操作系统管理,管理信号量及其信号量属性。

其次内核是怎样看待IPC资源(共享资源):

首先肯定有两部分:1.会有单独设计的一个模块。2.会有特定的保护机制。

所谓的信号量本身就是一个计数器,为了让进程通信,多个执行流共享同一份资源,而公共资源被并发访问就会产生数据不一致的问题,因此我们就需要保护我们的共享资源来面对同步与互斥的两个情况。

解决同步与互斥简单来说就是,互斥:任何一个时刻只允许一个执行流来使用该资源。同步:多个执行流都来使用该资源时,让他按照一定的顺序来执行。

信号量通俗点说,就是资源数目的计数器,每一个执行流想要访问资源内的某一份资源,不应该执行流直接访问,而是先申请信号量资源,(其实就是对计数器信号量--操作),申请成功后,就完成了对资源的预定机制,如果申请不成功,则执行流就进行阻塞。

我们在编写代码时如果想要访问这一份共享资源,先要申请信号量资源,如果成功,则返回之后的信号量,失败就阻塞。而阻塞的这一部分资源就是临界资源。

但也有特殊情况,只有一个信号量即只允许一个人访问的资源,这种信号量被叫做二元信号量,即就是一个锁的功能---互斥锁。

原子性:只有两种状态,要么不做,要么做完。

本次我们主要先 认识一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/707790.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【深度学习笔记】深度卷积神经网络——NiN

网络中的网络&#xff08;NiN&#xff09; LeNet、AlexNet和VGG都有一个共同的设计模式&#xff1a;通过一系列的卷积层与汇聚层来提取空间结构特征&#xff1b;然后通过全连接层对特征的表征进行处理。 AlexNet和VGG对LeNet的改进主要在于如何扩大和加深这两个模块。 或者&am…

Linux------进程地址空间

目录 一、进程地址空间 二、地址空间本质 三、什么是区域划分 四、为什么要有地址空间 1.让进程以统一的视角看到内存 2.进程访问内存的安全检查 3.将进程管理与内存管理进行解耦 一、进程地址空间 在我们学习C/C的时候&#xff0c;一定经常听到数据存放在堆区、栈区、…

4、正则表达式、本地存储

一、正则表达式 1、定义 用事先定义好的一些特定字符&#xff0c;这样的字符组合&#xff0c;组合成一个“规则字符串” 2、正则的组成 特殊字符 字母、数字、下划线、中文、特殊字符… 元字符&#xff08;常用&#xff09; 1、\d 匹配至少有一个数字 var reg /\d/ /…

SpringBoot整合rabbitmq-直连交换机队列(二)

说明&#xff1a;本文章主要是Direct定向/直连类型交换机的使用&#xff0c;它的大致流程是将一个队列绑定到一个直连交换机上&#xff0c;并赋予一个路由键 routingkey&#xff0c;当一个消息携带着路由值为routingkey&#xff0c;这个消息通过生产者发送给交换机时&#xff0…

【冲击蓝桥篇】动态规划(下):你还在怕动态规划!?进来!答题模板+思路解析+真题实战

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《数据结构与算法&#xff1a;初学者入门指南》&#x1f4d8;&am…

Python中检查一个数字是否是科技数的完整指南

目录 前言 什么是科技数&#xff1f; 如何判断一个数字是否是科技数&#xff1f; 分割数字并计算平方 Python实现科技数检测的示例代码 科技数的应用场景 1. 数字游戏 2. 数据处理 3. 算法优化 4. 数据结构设计 总结 前言 科技数&#xff08;Tech Number&#xff09;是一…

(二十三)Flask之高频面试点

目录&#xff1a; 每篇前言&#xff1a;Q1&#xff1a;为什么把request和session放在一起&#xff1f;Q2&#xff1a;Local对象的作用&#xff1f;Q3:&#xff1a;LocalStack对象的作用&#xff1f;Q4&#xff1a;一个运行中的Flask应用程序分别包括几个Local/LocalStack&#…

若依前后端分离版开源项目学习

前言&#xff1a;vscode中vue代码没有高亮显示&#xff0c;可以下载vetur插件解决&#xff0c;ctrl点击无法跳转函数定义问题&#xff0c;可以下载vue-helper插件解决&#xff1b;idea中ctrl点击函数即可跳转函数定义。 一、登录 1.生成验证码 基本思路&#xff1a; 后端生…

vue a-table 实现指定字段相同数据合并行

vue a-table 实现相同数据合并行 实现效果代码实现cloums数据格式数据源格式合并代码 实现效果 代码实现 cloums数据格式 const getColumns function () {return [{title: "分类",dataIndex: "checked",width: "150px",customRender: (text, …

JMeter--9.录制脚本

录制步骤 1.新建线程组&#xff1a;测试计划->线程->线程组 测试计划下&#xff0c;至少要有1个线程组&#xff0c;因为在录制器中需要选择【目标控制器】 2. 新建录制器&#xff1a;测试计划->非测试原件->HTTP(S)测试脚本记录器&#xff08;HTTP代理服务器&…

Ansible自动化运维(四)jinja2 模板、Roles角色详解

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01; &#x1f40b; 希望大家多多支…

Springboot+vue的考务报名平台(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的考务报名平台&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的考务报名平台&#xff0c;采用M&#xff08;model&#xff0…

vue2后台管理系统demo,包含增删查改、模糊搜索、分页

因一直敲小程序&#xff0c;vue不熟练&#xff0c;自己练手项目&#xff0c;就包含增删查改以及模糊搜索分页 一、页面简单但功能齐全 二、数据是mock模拟 三、启动步骤 1、 json-server --watch data.json 启动mock数据 2、npm i 下载依赖 3、npm run serve 四、github地址…

ETH网络中的账户

ETH网络中的账户 Externally owned accounts (EOA) - 外部账户 由用户控制&#xff0c;我们导入助记词创建的账户就属于此类账户。 Contract accounts (smart contracts) - 合约账户 合约账户由以太坊虚拟机执行的代码控制。它也被称为智能合约。合约帐户有相关的代码和数据存…

Redis的高性能之道

前言&#xff1a;做码农这么多年&#xff0c;我也读过很多开源软件或者框架的源码&#xff0c;在我看来&#xff0c;Redis是我看过写得最优美、最像一件艺术品的软件&#xff0c;正如Redis之父自己说的那样&#xff0c;他宁愿以一个糟糕的艺术家身份而不是一名好程序员被别人记…

探索AI视频模型的无限可能:OpenAI的Sora引领创新浪潮

文章目录 &#x1f4d1;前言一、技术解析二、应用场景三、未来展望四、伦理与创意五、用户体验与互动&#x1f324;️总结 &#x1f4d1;前言 随着人工智能技术的蓬勃发展&#xff0c;AI视频模型正逐渐成为科技领域的新宠。在这个变革的浪潮中&#xff0c;OpenAI推出的首个AI视…

算法沉淀——动态规划之回文串问题(上)(leetcode真题剖析)

算法沉淀——动态规划之回文串问题 01.回文子串02.最长回文子串03.分割回文串 IV04.分割回文串 II05.最长回文子序列06.让字符串成为回文串的最少插入次数 01.回文子串 题目链接&#xff1a;https://leetcode.cn/problems/palindromic-substrings/ 给你一个字符串 s &#xf…

雾锁王国服务器官方配置要求说明

雾锁王国/Enshrouded服务器CPU内存配置如何选择&#xff1f;阿里云服务器网aliyunfuwuqi.com建议选择8核32G配置&#xff0c;支持4人玩家畅玩&#xff0c;自带10M公网带宽&#xff0c;1个月90元&#xff0c;3个月271元&#xff0c;幻兽帕鲁服务器申请页面 https://t.aliyun.com…

【机器人最短路径规划问题(栅格地图)】基于蚁群算法求解

基于蚁群算法求解机器人最短路径规划问题的仿真结果 仿真结果 收敛曲线变化趋势 蚁群算法求解最优解的机器人运动路径 各代蚂蚁求解机器人最短路径的运动轨迹