Linux_进程通信_管道_system V共享内存_6

文章目录

  • 一、进程通信分类
  • 二、管道
    • 1.什么是管道
      • 1.原理
      • 2.管道的特点
    • 2.匿名管道
    • 3.命名管道
      • 1.创建命名管道文件 - mkfifo (命令)
      • 2.创建命名管道文件 - mkfifo (函数)
  • 三、system V共享内存
    • 1.原理
    • 2.共享内存函数
      • 1.fotk
      • 2.shmget
        • 1.如何知道有哪些IPC资源 - ipcs (命令)
        • 2.如何显示删除 - ipcrm (命令)
      • 3.如何使用共享内存 - shmat - shmdt
      • 4.系统接口删共享内存 -shmctl
  • 四、进程互斥
    • 1.临界资源
    • 2临界区
    • 3.原子性
    • 4.互斥


通信背景:
1.进程是具有独立性的,但进程间想要交互数据(多进程协同处理一件事情),成本会非常高 。
2.不要以为,进程独立了,就是彻底独立,我们需要双方能够进行一定程度的信息交互。

一、进程通信分类

  1. 管道
    a.匿名管道
    b.命名管道
  2. System V IPC
    a.System V 消息队列
    b.System V 共享内存
    c.System V 信号量
  3. POSIX IPC
    a.消息队列
    b.共享内存
    c.信号量
    d.互斥量
    e.条件变量
    f.读写锁

二、管道

1.什么是管道

通信之前,让不同的进程看到同一份资源(文件,内存块…)。我们要学的进程间通信,不是告诉我们如何通信,而是让两个进程看到同一份资源,因为资源不同,所以决定了不同种类的通信方式,而管道就是提供共享资源的一种手段。

管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道“
在这里插入图片描述

1.原理

在这里插入图片描述
站在文件角度看管道:
在这里插入图片描述
站在内核角度看管道:

在这里插入图片描述

简单来说,看待管道,就如同看待文件一样,(不过是不在磁盘而是在内存里的文件)!管道的使用和文件一致,迎合了“Linux一切皆文件思想”。

为什么父进程要分别打开读写?
为了子进程继承,让子进程不用再打开了!
为什么父子要关闭对应的读写?
管道必须是单向通信
谁决定父子关闭什么读写?
不是由管道本身决定的,是由需求决定的!

2.管道的特点

生活中的管道都有什么共同特点:
a.都是单向的!
b.管道传输资源的
所以进程间通信管道是单向的,传输数据的!

2.匿名管道

创建管道——系统接口pipe
在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<unistd.h>
#include<cstring>
#include<sys/types.h>
#include<sys/wait.h>
using namespace std;
int main()
{//1.创建管道int pipefd[2] = {0};if(pipe(pipefd)!=0){cerr<<"pipe error"<<endl;return 1;}//pipefd[0] 是读端//pipefd[1] 是写端//快速记忆  读写-01 0就是读 1就是写//2.创建子进程pid_t id = fork();if(id<0){cerr<<"fork error"<<endl;return 2;}else if(id==0){//child//子进程进行读取,要关闭写端close(pipefd[1]);#define NUM 1024char buffer[NUM];while(true){memset(buffer,'\0',sizeof(buffer));//read返回值//0表示管道对端已经关闭,那么子进程是如何知道 ?//管道也是类似文件,和文件一样有硬链接数,当硬链接数为1时表示只有子进程在读,就表示对端已经关闭了。//大于0表示读到的字符长度//-1表示读取错误ssize_t s = read(pipefd[0],buffer,sizeof(buffer)-1);if(s>0){//读取成功buffer[s] = '\0';cout<<"子进程收到消息,内容是: "<<buffer<<endl;}else if(s==0){//父进程关闭管道cout<<"父进程写完了,我也退出啦"<<endl;break;}else{cerr<<"read error"<<endl;return 3;}}close(pipefd[0]);}else{//parent//父进程来进行写入,要关闭读端close(pipefd[0]);string msg = "你好子进程,我的父进程!,这次发送的信息编号是";int cnt = 0;while(cnt<5){char sendBuffer[1024];sprintf(sendBuffer,"%s : %d",msg.c_str(),cnt);//不用把'\0'也写进去write(pipefd[1],sendBuffer,strlen(sendBuffer));sleep(1);cnt++;}close(pipefd[1]);cout<<"父进程写完了"<<endl;pid_t res  =waitpid(id,nullptr,0);if(res>0){cout<<"等待子进程成功"<<endl;}}return 0;
}

在这里插入图片描述
运行上面的代码发现现象:
当父进程没有写入数据的时候,子进程在等!所以,父进程写入之后,子进程才会read(会返回)到数据,子进程打印读取数据要以父进程的节奏为主!
父进程和子进程读写的时候,是有一定的顺序的!!->父子进程各自printf的时候(向显示器写入),会有顺序吗?
不会,而这种乱序,就是缺乏访问控制。
管道内部,没有数据,reader就必须阻塞等待(read)——等管道有数据
管道内部,如果数据被写满,writer就必须阻塞等待(write)——等管道有空间
pipe内部,自带访问控制机制——同步和互斥机制!
阻塞等待,在哪个等待队列里等待?
管道资源的等待队里等待。

特征总结:
1.管道只能用来进行具有血缘关系的进程之间,进行进程通信。通常用于父子通信
2.管道只能单向通信(内核实现决定的),半双工的一种特殊情况
3.管道自带同步机制(pipe满,writer等。pipe空,reader等)——自带访问控制
4.管道是面向字节流的——先写的字符,一定是先被读取的,没有格式边界,需要用户来定义区分内容的边界
5.管道的生命周期——管道是文件吗?是——进程退出了,曾经打开的文件会怎么办?退出

3.命名管道

用于毫不相干的进程之间进行通信。

1.创建命名管道文件 - mkfifo (命令)

mkfifo 管道名

在这里插入图片描述
在这里插入图片描述

2.创建命名管道文件 - mkfifo (函数)

在这里插入图片描述

命名管道:通过一个fifo文件,有路径就 可以确认唯一性,通过路径找到同一个资源。

#include <iostream>
#include <sys/types.h>
#include 
#define IPC_PATH "./.fifo"
using namespace std;int main()
{if (mkfifo(IPC_PATH,0600)!=0){cerr<<"mkfifo error"<<endl;return 1;}
}

运行代码就创建了命名管道:
在这里插入图片描述
使用就和用文件一样,open,read,write。

三、system V共享内存

进程间通信的前提是:先让不同的进程,看到同一份资源!

1.原理

在这里插入图片描述

2.共享内存函数

1.fotk

作用:生成key值。


原型: key_t ftok(const char *pathname, int proj_id);


参数:
pathname :路径
proj_id :数字


返回值:成功返回key值,失败返回-1。

#pragma once
#include<iostream>
#include<sys/types.h>
#include<sys/ipc.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>#define PATH_NAME "/home/whc/study/24_4_1"
#define PROJ_ID 0x14key_t Creatkey()
{key_t key =  ftok(PATH_NAME,PROJ_ID);if(key<0){std::cerr<<"Creatkey error"<<strerror(errno)<<std::endl;exit(1);}
}using namespace std;
int main()
{key_t key = Creatkey();std::cout<<"key:"<<key<<endl;return 0;
}

在这里插入图片描述

2.shmget

在这里插入图片描述
作用:用来创建共享内存


原型 :int shmget(key_t key, size_t size, int shmflg);


参数:
key:这个共享内存段名字

size:共享内存大小,建议设置成为页(4KB)的整数倍

shmflg:它们的用法和创建文件时使用的mode模式标志是一样的
IPC_CREAT:创建共享内存,如果已经存在,就获取之,不存在,就创建之
IPC_EXCL:不单独使用,必须和IPC_CREAT配合使用。如果不存在指定的共享内存,创建之,如果存在了,出错返回。可以保证,如果shmegt函数调用成功,一定是一个全新的share
memory!
0600:权限


返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1

共享内存存在哪?
内核中,内核会给我们维护发现内存的结构!
对于OS来说,共享内存也要被管理起来,如何管理,先描述,再组织!
struct shmid_ds{
//各种数据
key_t kye;
};

我怎么知道,这个共享内存属于存在还是不存在?
先有方法,标识共享内存的唯一性,就是上面说的key。而这个key值一般是由用户提供的,让他们拥有同一个key值。

匿名管道通过约定使用同一文件。
共享内存通过约定使用同一个唯一key,来进行通信的!!

#include<iostream>
#include<time.h>
#include<iostream>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<string.h>
#include<errno.h>
#include<unistd.h>#define PATH_NAME "/home/whc/study/24_4_1"
#define PROJ_ID 0x14
#define MEM_SIZE 4096key_t Creatkey()
{key_t key =  ftok(PATH_NAME,PROJ_ID);if(key<0){std::cerr<<"Creatkey error"<<strerror(errno)<<std::endl;exit(1);}
}
std::ostream &Log()
{std::cout<<"For Debug | "<<"timestamp:"<<(uint64_t)time(nullptr)<<"  | ";return std::cout;
}
using namespace std;
int main()
{key_t key = Creatkey();Log() << "key:" << key << endl;int shmid = shmget(key,MEM_SIZE,IPC_CREAT|IPC_EXCL|0600);if(shmid<0){Log()<<"shmget: "<<strerror(errno)<<endl;return 2;}Log()<<"create shm success, shmid "<<shmid<< endl;return 0;
}

在这里插入图片描述
当我们运行完毕创建全新共享内存的代码后(代码退出),但是第二(n)次时候,该代码无法运行,告诉我们file存在,共享内存是存在的,system v下的共享内存的生命周期是内核的。如果不显示的删除,只能通过kernel(OS)重启来解决。

1.如何知道有哪些IPC资源 - ipcs (命令)

作用:查看当前用户创建的共享内存

ipcs -m

在这里插入图片描述

2.如何显示删除 - ipcrm (命令)
ipcrm -m shmid

在这里插入图片描述

3.如何使用共享内存 - shmat - shmdt

在这里插入图片描述
作用:将共享内存和自己的进程产生关联attach


原型:void *shmat(int shmid, const void *shmaddr, int shmflg);


参数 :
shmid : shmid
shmaddr : 不管 设为nullptr
shmflg : 是读还是写,不管设为默认:0


返回值:
出错返回-1,成功返回地址空间,怎么使用malloc的空间,就怎么使用共享内存的空间!

shmat(shmid,nullptr,0);

作用:将共享内存和直接的进程去关联detach


原型:int shmdt(const void *shmaddr);


参数:
shmaddr:就是shmat的返回值


返回值:失败返回-1

    //关联char *str = (char*)shmat(shmid, NULL, 0);Log()<<"attach shm: "<<shmid<< " success\n";sleep(5);//用共享内存while(true){cout<<"."<<str<<endl;sleep(1);}//去关联shmdt(str);Log()<<"detach shm: "<<shmid<<" succsee\n";
    // 关联char *str = (char *)shmat(shmid, nullptr, 0);// 用它//我们把共享内存实际上是映射到了我们进程地址空间的用户空间了(堆栈之间),对每一个进程而言//挂接到自己的上下文的共享内存,属于自己的空间,类似于堆空间或者栈空间,可以被用户直接使用。int cnt = 0;while (cnt < 26){str[cnt] = 'A' + cnt;cnt++;str[cnt] ='\0';sleep(1);}// 去关联shmdt(str);

在这里插入图片描述

共享内存,因为他自身的特性,他没有任何访问控制,共享内存被双方之间看到,属于双方的用户空间,可以直接通信,但是不安全! 共享内存是所有进程通信,速度最快的!

4.系统接口删共享内存 -shmctl

在这里插入图片描述

作用:删除共享内存


原型:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);


参数:
shmid:shmid

cmd : 如果要删除就传 IPC_RMID

buf:nullptr


返回值:-1就是失败

shmid(shmid,IPC_RMID,nullptr);

四、进程互斥

1.临界资源

被多个进程,能够看到的资源——临界资源。
如果没有对临界资源进行任何保护,对于临界资源的访问,双方进程在进行方法的时候,就都是乱序,可能会因为读写交叉而导致各种乱码,废弃数据,访问控制方法的问题!

2临界区

对于多个进程而言,访问临界资源的代码——临界区
我的进程中,有大量的代码没有访问临界资源,而只有一部分代码才会访问临界资源。

3.原子性

一件事,要么没做,要么做完了,没有中间状态——原子性

4.互斥

任何时刻,只允许一个进程,访问临界资源——互斥

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

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

相关文章

河海大学-海洋学院2024年硕士研究生调剂通知

一、调剂专业及计划具体调剂专业及计划可参见河海大学研究生院官网《河海大学2024年硕士研究生调剂通知》和附件。 二、调剂报名与复试要求 1.报名条件&#xff1a;调剂原则见《河海大学202 4年硕士研究生调剂通知》&#xff0c;详细要求见中国研究生招生信息网“全国硕士研究…

Mysql密码修改问题

docker安装mysql&#xff0c;直接拉取镜像&#xff0c;挂载关键目录即可启动&#xff0c;默认3306端口。此时无法直接连接&#xff0c;需要配置密码。docker进入mysql容器中 docker exec -it mysql bash #mysq是容器名称&#xff0c;也可以用容器id通过修改mysql的配置进行免密…

Unity类银河恶魔城学习记录12-7-1 p129 Craft UI - part 1源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili UI_CraftList.cs using System.Collections; using System.Collections.Gen…

Vue基础知识:Vue路由——重定向,以及?(可选符)的使用

当网页打开时&#xff0c;url默认是/路径&#xff08;根路径&#xff09;&#xff0c;未匹配到组件时&#xff0c;会出现空白&#xff0c;为了解决这个问题 就要利用重定向 重定向&#xff1a;匹配path后&#xff0c;强制跳转path路径 重定向的语法&#xff1a; {path:匹配…

【Linux】使用cloudreve搭建个人网盘并传输文件

Cloudreve 是一个开源的个人网盘系统&#xff0c;能够帮助用户搭建属于自己的私有云存储服务。它支持多种存储后端&#xff0c;包括本地存储、远程FTP/SFTP存储、以及云存储服务如阿里云OSS、腾讯云COS和Amazon S3等。Cloudreve具有友好的用户界面和丰富的功能&#xff0c;比如…

如何使用开源情报跟踪一个人?在线访问网站以及使用方法介绍

如何使用开源情报跟踪一个人&#xff1f;在线访问网站以及使用方法介绍。 开源情报&#xff08;OSINT&#xff09;是一门关于收集和分析公开可用信息的独特技艺&#xff0c;它致力于构建个人或团体的详尽档案。 这一过程中&#xff0c;信息搜集者会利用多元化的信息源&#xff…

SQLite 查询优化器概述(九)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite中的隔离(八&#xff09; 下一篇&#xff1a;SQLite下一代查询规划器(十&#xff09; 1. 引言 本文档概述了查询规划器和优化器如何 用于 SQLite 工作。 给定一个 SQL 语句&#xff0c;可能有几十个、几百…

Java: LinkedList的模拟实现

一、双向链表简介 上一篇文章我介绍了单向链表的实现&#xff0c;单向链表的特点是&#xff1a;可以根据上一个节点访问下一个节点&#xff01;但是&#xff0c;它有个缺点&#xff0c;无法通过下一个节点访问上一个节点&#xff01;这也是它称为单向链表的原因。 那么&#x…

C++面向对象程序设计 - 共用数据的保护(常对象、常指针和常引用)

C虽然采取了不少有效的措施&#xff08;如设private保护&#xff09;以增加数据的安全性&#xff0c;但是有些数据却往往是共享的&#xff0c;例如实参与形参&#xff0c;变量与其引用&#xff0c;数据与其指针等&#xff0c;人们可以在不同的场合通过不同的途径访问同一个数据…

【QT+QGIS跨平台编译】056:【pdal_arbiter+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

点击查看专栏目录 文章目录 一、pdal_arbiter介绍二、pdal下载三、文件分析四、pro文件五、编译实践一、pdal_arbiter介绍 pdal_arbiter是 PDAL 项目的一个库,用于帮助管理应用程序运行在 EC2 实例上的 AWS 凭证。 当应用程序需要调用 AWS API 时,它们必须使用 AWS 凭据对 AP…

AI预测福彩3D第28弹【2024年4月6日预测--第7套算法重新开始计算第1次测试】

今天开始&#xff0c;咱们开始进行第7套算法的测试&#xff0c;第7套算法将综合012路权重、012路直选及012路和值进行预测。好了&#xff0c;先上图后上结果吧~ 2024年4月6日福彩3D的七码预测结果如下 第一套&#xff1a; 百位&#xff1a;1 2 4 5 7 8…

全志 Linux Qt

一、简介 本文介绍基于 buildroot 文件系统的 QT 模块的使用方法&#xff1a; • 如何在 buildroot 工具里编译 QT 动态库&#xff1b; • 编译及运行 qt_demo 应用程序&#xff1b; • 适配过程遇到的问题。 二、QT动态库编译 在项目根路径执行 ./build.sh buildroot_menuc…

武汉星起航:打造亚马逊一站式孵化平台引领电商新风潮

2020年正式成立后&#xff0c;武汉星起航持续深耕亚马逊自营店铺运营&#xff0c;不断拓展跨境电商业务。公司凭借专业运营团队和多年经验为合作伙伴提供深入合作模式&#xff0c;迅速崭露头角。推出亚马逊一站式孵化平台&#xff0c;为卖家提供全方位支持&#xff0c;彰显了公…

[RAM] HBM 导论 | 为什么我们需要 HBM?

主页&#xff1a; 元存储博客 文章目录 前言1. 什么是 HBM2. HBM 发展2.1 HBM 起源2.2 HBM 简史 3. HBM 3D 结构原理4. 为什么需要 HBM5. HBM 生产商家6. HBM 封装厂家7. HBM 应用8. HBM 挑战8.1 工艺成本8.2 量产良率问题8.3 散热问题 总结 前言 在AI时代的浪潮中&#xff0c…

vue项目入门——index.html和App.vue

vue项目中的index.html文件 在Vue项目中&#xff0c;index.html文件通常作为项目的入口文件&#xff0c;它包含了Vue应用程序的基础结构和配置。 该文件的主要作用是引入Vue框架和其他必要的库&#xff0c;以及定义Vue应用程序的启动配置。 import Vue from vue import App …

Android Studio学习8——点击事件

在xml代码中绑定 在java代码中绑定 弹出一个toast 随机&#xff0c;数组

H5 点击图片翻转效果

需求 ☑ h5 实现点击图片得到的是放大的镜像图片&#xff08;不是放大镜效果 而是实现图片镜像对折&#xff0c;左右翻转&#xff09; ☑ 鼠标点击后原图消失/隐藏&#xff0c;在原来的位置上取而代之的是翻转后的图&#xff08;除了翻转之外不要改变其他的性质&#xff0c;比…

Langchain教程 | langchain+OpenAI+PostgreSQL(PGVector) 实现全链路教程,简单易懂入门

前提&#xff1a; 在阅读本文前&#xff0c;建议要有一定的langchain基础&#xff0c;以及langchain中document loader和text spliter有相关的认知&#xff0c;不然会比较难理解文本内容。 如果是没有任何基础的同学建议看下这个专栏&#xff1a;人工智能 | 大模型 | 实战与教程…

【CicadaPlayer】demuxer_service中DASH的简单理解

DASH协议 dash 是属于demuxer模块的 MPEG-DASH是一种自适应比特率流技术,可根据实时网络状况实现动态自适应下载。和HLS, HDS技术类似, 都是把视频分割成一小段一小段, 通过HTTP协议进行传输,客户端得到之后进行播放;不同的是MPEG-DASH支持MPEG-2 TS、MP4(最新的HLS也支持…

Linux 多线程

目录 初识线程 线程的概念 Linux下的线程 线程优缺点 线程控制 线程创建 线程终止 线程等待 线程分离 线程取消 其它 线程互斥 互斥的概念 互斥锁的使用 锁的本质 线程同步 线程同步的概念 条件变量的概念 条件变量的使用 信号量 信号量的概念 信号量接口…