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为key
    key_t key=ftok(pathname.c_str(),proj_id);//convert a pathname and a project identifier to a System V IPC key
    if(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,错误返回-1
     if(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.mfbz.cn/a/414739.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

浅谈 Linux fork 函数

文章目录 前言fork 基本概念代码演示示例1&#xff1a;体会 fork 函数返回值的作用示例2&#xff1a;创建多进程&#xff0c;加深对 fork 函数的理解 前言 本篇介绍 fork 函数。 fork 基本概念 pid_t fork(void) fork 的英文含义是"分叉"&#xff0c;在这里就是 …

web安全学习笔记【15】——信息打点(5)

信息打点-CDN绕过&业务部署&漏洞回链&接口探针&全网扫描&反向邮件 #知识点&#xff1a; 1、业务资产-应用类型分类 2、Web单域名获取-接口查询 3、Web子域名获取-解析枚举 4、Web架构资产-平台指纹识别 ------------------------------------ 1、开源-CMS指…

非线性优化资料整理

做课题看了一些非线性优化的资料&#xff0c;整理一下&#xff0c;以方便查看&#xff1a; 优化的中文博客 数值优化|笔记整理&#xff08;8&#xff09;——带约束优化&#xff1a;引入&#xff0c;梯度投影法 (附代码)QP求解器对比对于MPC的QP求解器 数值优化| 二次规划的…

day02_前后端环境搭建(前端工程搭建,登录功能说明,后端项目搭建)

文章目录 1. 软件开发介绍1.1 软件开发流程1.2 角色分工1.3 软件环境1.4 系统的分类 2. 尚品甄选项目介绍2.1 电商基本概念2.1.1 电商简介2.1.2 电商模式B2BB2CB2B2CC2BC2CO2O 2.2 业务功能介绍2.3 系统架构介绍2.4 前后端分离开发 3. 前端工程搭建3.1 Element-Admin简介3.2 El…

漫漫数学之旅034

文章目录 经典格言数学习题古今评注名人小传 - 大卫希尔伯特 经典格言 研究数学的艺术在于发现包含普遍性萌芽的特殊情形。——大卫希尔伯特&#xff08;David Hilbert&#xff09; 亲爱的朋友&#xff0c;让我们一起进入数学的奇幻世界&#xff0c;那里大卫希尔伯特就像一位智…

LightSNS V1.6.6.0版轻社区解锁版源码优化版

优化&#xff1a;后台面板首页数据统计改成异步加载 优化&#xff1a;同一内容重复评论提示 优化&#xff1a;vip到期个人主页vip专属背景还保留问题 优化&#xff1a;活动报名名额为空可能导致的问题 优化&#xff1a;移动端评论框左下“转发动态”改为“转发内容” 优化&…

【C++】树形关联式容器set、multiset、map和multimap的介绍与使用

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.关联式容器 2.键…

Linux笔记--用户与用户组

Linux系统是一个多用户多任务的操作系统&#xff0c;任何一个要使用系统资源的用户&#xff0c;都必须首先向系统管理员(root)申请一个账号&#xff0c;然后以这个账号的身份进入系统。 用户的账号一方面可以帮助系统管理员对使用系统的用户进行跟踪&#xff0c;并控制他们对系…

python接口自动化测试 —— unittest框架suite、runner详细使用!

test suite 测试套件&#xff0c;理解成测试用例集一系列的测试用例&#xff0c;或测试套件&#xff0c;理解成测试用例的集合和测试套件的集合当运行测试套件时&#xff0c;则运行里面添加的所有测试用例 test runner 测试运行器用于执行和输出结果的组件 test suite、tes…

【前端素材】推荐优质后台管理系统Salreo平台模板(附源码)

一、需求分析 当我们从多个层次来详细分析后台管理系统时&#xff0c;可以将其功能和定义进一步细分&#xff0c;以便更好地理解其在不同方面的作用和实际运作。 1. 结构层次 在结构层次上&#xff0c;后台管理系统可以分为以下几个部分&#xff1a; a. 辅助功能模块&#…

PostgreSQL:开源巨人的崛起和不可阻挡的发展

PostgreSQL&#xff1a;开源巨人的崛起和不可阻挡的发展 PostgreSQL是一款开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;以其强大的功能和持续的发展势头在数据库领域崭露头角。本文将探讨为什么PostgreSQL的发展势不可挡&#xff0c;从开源精神和强大…

GridView 演示(P28 5.4GridView)

一、目标效果 如下图所示&#xff0c;我们通过 GridView 新建100个子项&#xff0c;每个子项上写有自己的 index。 二、具体实现代码 1. Main.qml import QtQuickWindow {width: 640height: 480visible: truetitle: qsTr("GridView 演示")GridView{anchors.fill…

探索NebulaGraph:一个开源分布式图数据库的技术解析

欢迎关注微信公众号&#xff1a;一休哥助手。多种功能等待你的使用。1. 介绍 NebulaGraph的定位和用途 NebulaGraph是一款开源的分布式图数据库&#xff0c;专注于存储和处理大规模图数据。它的主要定位是为了解决图数据存储和分析的问题&#xff0c;能够处理节点和边数量巨大…

林浩然与杨凌芸的Scala编程历险记:变量与数据类型的魔法对决

林浩然与杨凌芸的Scala编程历险记&#xff1a;变量与数据类型的魔法对决 在Scala世界的梦幻殿堂中&#xff0c;两位英勇的程序员——林浩然和杨凌芸正准备开启一场代码之旅。这次&#xff0c;他们将深入探索Scala王国中的变量奥秘与数据类型丛林。 一、变量声明篇 &#xff0…

【DDD】学习笔记-领域驱动设计体系

从统一语言到限界上下文&#xff0c;从限界上下文到上下文映射&#xff0c;从领域分析建模到领域设计建模&#xff0c;再从领域设计建模到领域实现建模&#xff0c;我将软件架构设计、面向对象设计、场景驱动设计和测试驱动开发有机地融合起来&#xff0c;贯穿于领域驱动设计的…

数据结构:循环队列

一、队列的概念 操作受限的线性表&#xff0c;允许在队列的一端执行入队操作&#xff0c;另一端执行出队操作 先进先出(FIFO) 1.顺序队列 物理结构连续&#xff0c;依赖于数组实现 队列中有一个队头指针和队尾指针&#xff0c;队头指针保存每次要出队的元素&#xff0c;队…

使用Jenkins部署前端Vue项目和后端Java服务

Jenkins安装相关插件&#xff0c;供后续使用&#xff08;Dashboard - Manage Jenkins - Plugins&#xff09; Maven Integration plugin https://plugins.jenkins.io/maven-plugin CloudBees Docker Build and Publish pluginhttps://plugins.jenkins.io/docker-build-publish…

代码随想录算法训练营第64天/最后一天 | 84.柱状图中最大的矩形

今日任务 84.柱状图中最大的矩形 84.柱状图中最大的矩形 - Hard 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾…

Opencv实战(3)详解霍夫变换

霍夫变换 Opencv实战系列指路前文&#xff1a; Opencv(1)读取与图像操作 Opencv(2)绘图与图像操作 文章目录 霍夫变换1.霍夫线变换1.1 原理1.2 HoughLines() 2.霍夫圆变换2.1 原理2.2 HoughCircles() 最基本的霍夫变换是从黑白图像中检测直线(线段) 霍夫变换(Hough Transform…

第三百七十回

文章目录 1. 概念介绍2. 使用方法2.1 获取所有时区2.2 转换时区时间 3. 示例代码4. 内容总结 我们在上一章回中介绍了"分享一些好的Flutter站点"相关的内容&#xff0c;本章回中将介绍timezone包.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在…
最新文章