Linux---进程间通信(下)

news2024/11/16 3:15:42

1、System V 共享内存

原理如下图

 系统调用接口介绍

int shmget(key_t key, size_t size, int shmflg)

功能:用来创建共享内存
参数

  • key:这个共享内存段名字,内核用key来标识共享内存
  • size:共享内存大小
  • shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的(这里介绍两个:IPC_CREAT和IPC_EXCL,其中IPC_CREAT表示共享内存存在就返回,不存在就创建,IPC_EXCL不单独使用,IPC_EXCL | IPC_CREAT表示不存在就创建,存在就出错返回,作用是确保创建出来的共享内存一定是全新的)

返回值:成功返回一个非负整数,即该共享内存段的标识码(作用类似文件描述符fd);失败返回-1

void* shmat(int shmid, const void* shmaddr, int shmflg)

功能:将共享内存段连接到进程地址空间(在页表中创建映射关系)
参数

  • shmid:共享内存标识
  • shmaddr:指定连接的地址(可以直接传nullptr,让OS帮你分配)
  • shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY

返回值:成功返回一个指针,指向共享内存第一个节(类比malloc);失败返回-1

 int shmdt(const void *shmaddr)

功能:将共享内存段与当前进程脱离(删除页表中的映射关系)
参数

  • shmaddr:由shmat所返回的指针

返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段

int shmctl(int shmid, int cmd, struct shmid_ds *buf)

功能:用于控制共享内存
参数

  • shmid:由shmget返回的共享内存标识码
  • cmd:将要采取的动作(IPC_STAT---获取共享内存的相关信息、IPC_SET---设置共享内存的相关信息、IPC_RMID---释放共享内存)
  • buf:指向一个保存着共享内存的模式状态和访问权限的数据结构

返回值:成功返回0;失败返回-1

(共享内存的生命周期是随内核的,即进程结束,共享内存不会释放,需要手动释放空间)

 共享内存的通信代码如下

//comm.hpp

#include <string>
#include <iostream>
#include <sys/ipc.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <cstring>
using namespace std;

// 路径和项目id可以随便写,但是建议写和代码相关的
string pathname = "/shm";
int process_id=0x11223344;

const int size = 4096; // 建议设置为n*4096,Linux以4096为单位进行分配共享内存
string filename = "fifo"; //管道名,下面代码用管道是利用管道的同步机制,共享内存没有同步机制

key_t Getkey()
{
    key_t key = ftok(pathname.c_str(), process_id);// 该系统调用相当于一个hash函数,用两个参数通过算法获得一个hash值 key
    if(key < 0)
    {
        cout << "errno: " << errno << ",errstring: " << strerror(errno) << endl;
        exit(1);
    }
    
    return key;
}

string ToHex(int id) // 返回16进制表示形式 
{
    char buffer[1024];
    snprintf(buffer,sizeof(buffer),"0x%x",id);
    return buffer;
}

int CreateShmHelper(key_t key, int flag)
{
    int shmid = shmget(key, size, flag);
    if(shmid < 0)
    {
        cout << "errno: " << errno << ",errstring: " << strerror(errno) << endl;
        exit(2);
    }
    return shmid;
}

int GetShm(key_t key)
{
    return CreateShmHelper(key, IPC_CREAT);
}

int CreateShm(key_t key)
{
    return CreateShmHelper(key, IPC_CREAT|IPC_EXCL|0666);// 设置创建共享内存并设置权限0666---八进制
}


//server.cc

#include "comm.hpp"
//用一个类来初始化资源和释放资源
class Init
{
public:
    Init()
    {
        int n = mkfifo(filename.c_str(), 0666);
        if(n < 0) exit(1);

        key_t key = Getkey();
        cout << "key:" << ToHex(key) << endl;
        // sleep(5);
        // key vs shmid
        // key:内核中使用,标识共享内存的唯一性
        // shmid:应用这个共享内存的时候,我们使用shmid来使用操作共享内存
        // 即key是给内核看的,shmid是给用户看的
        shmid = CreateShm(key);
        cout << "shmid:" << shmid << endl;
        cout << "创建内存" << endl;

        p = (char*)shmat(shmid, nullptr, 0);
        cout << "将内存挂接到虚拟地址空间" << endl;
        sleep(3);
//注意资源的初始化顺序,管道的打开要放在恰当的地方,不然会出bug,这边建议放到最后
        fd = open(filename.c_str(), O_RDONLY);// 读端
    }

    ~Init()
    {
        close(fd);
        unlink(filename.c_str());// 删除管道文件

        shmdt(p);
        cout << "删除页表映射" << endl;
        sleep(3);

        shmctl(shmid, IPC_RMID, nullptr);
        cout << "删除内存" << endl;
    }
public:
    int fd;
    int shmid;
    char*p;
};

int main()
{
    Init init;
    int code = 0;
    while(1)
    {
        ssize_t n = read(init.fd, &code, sizeof(code));
        if(n > 0)
        {
            cout << "client:" << init.p << endl;
        }
        else if(n == 0)
        {
            break;
        }
    }
    return 0;
}

//client.cc
#include "comm.hpp"

int main()
{
    key_t key = Getkey();
    cout << "key:" << ToHex(key) << endl;

    int shmid = GetShm(key);
    cout << "获取shmid:" << shmid << endl;

    char *p = (char *)shmat(shmid, nullptr, 0); // 开出来的空间当数组用即可
    cout << "挂接" << endl;

    int fd = open(filename.c_str(), O_WRONLY);
    int code = 1;
    cout << "write start" << endl;
    for (int i = 0; i < 26; i++)
    {
        p[i] = 'a' + i;
        sleep(2);
        write(fd, &code, sizeof(code));
        cout << "write:" << (char)('a' + i) << endl;
    }
    shmdt(p);
    cout << "取消映射" << endl;

    return 0;
}

在看完上面这段代码的前提下,我们就能解释两个进程如何得到同一个共享内存的标识符:本质是我们事先约定了标识符key的值(在上面的代码中,我们是用ftok函数生成的key,使用的相同的参数,所以返回值也相同。这里使用ftok只是让系统帮助我们生成key,其实只要key这个值相对其他共享内存的key是唯一的即可),放在头文件中,然后两个程序通过key就能找到同一个共享内存

特点:

  • 共享内存的通信方式,不会提供同步机制,共享内存是直接裸露给所有的使用者的,一定要注意共享内存的使用安全问题
  • 共享内存可以提供较大的空间
  • 共享内存是所有进程间通信速度最快的(因为管道底层是对文件操作的复用,所以数据需要在用户缓冲区和内核文件缓冲区间来回拷贝,但是共享内存不需要,共享内存可以理解为用malloc申请了一块空间,两个进程都能看见,没有用户缓冲区和内核文件缓冲区来回拷贝的过程,所以更快)

查看管理ipc资源的指令介绍

 ipcs -m

ipcrm -m shmid   删除共享内存

2、System V 消息队列---简单介绍

消息队列提供一个进程给另一个进程发送数据块的能力

3、System V信号量---简单介绍

背景介绍

当我们在进行进程间通信的时候,可能会出现A进程和B进程通过同一份资源在进行通信,突然C进程也开始往该资源中写数据/读数据,导致数据传输出现问题的情况,换句话说,当多执行流访问同一份资源时,我们需要保护该资源,所以我们有了信号量这个概念

在介绍信号量的概念之前,我们先来看看信号量(semaphore)的系统调用接口

信号量的概念和理解

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

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

相关文章

留子厨房开发日志

以下记录了使用go语言框架Beego&#xff0c;Mysql数据库&#xff0c;Redis数据库实现一个点菜/菜谱应用API的全过程。 技术方案 github地址 数据库设计 新建数据库&#xff1a; CREATE DATABASE menu;新建数据表&#xff1a; CREATE TABLE menu ( id int(10) unsigned NOT …

Docker 第十九章 : 阿里云个人镜像仓使用

Docker 第十九章 : 阿里云个人镜像仓使用 本章知识点: 如何创建镜像库,如何设置密码,如何登录与退出个人镜像仓,如何本地打镜像,如何将本地镜像推送到个人镜像库。 背景 在项目YapiDocker部署中,因读取mongo:latest 版本不一致,导致后续执行步骤的异常。遇到此场景…

OpenCV Mat实例详解 六

本文将接着OpenCV Mat实例详解继续介绍OpenCV Mat类的操作符及公有成员函数。 Mat & operator Mat & operator (const Mat &m) 将一个Mat对象赋值个另一个Mat对象。 Mat & operator (const MatExpr &expr) 将一个Mat表达式值赋值给Mat对象 Mat & op…

【高德地图】Android高德地图绘制标记点Marker

&#x1f4d6;第4章 Android高德地图绘制标记点Marker ✅绘制默认 Marker✅绘制多个Marker✅绘制自定义 Marker✅Marker点击事件✅Marker动画效果✅Marker拖拽事件✅绘制默认 Infowindow&#x1f6a9;隐藏InfoWindow 弹框 ✅绘制自定义 InfoWindow&#x1f6a9;实现 InfoWindow…

Covalent Network(CQT)与 Movement Labs 达成合作,重新定义 M2 系统区块链数据可用性与性能

Covalent Network&#xff08;CQT&#xff09;是行业领先的多链索引器&#xff0c;正在与 Movement Labs 的 M2 展开具有突破性意义的合作。M2 是以太坊上的首个 Move-EVM&#xff08;MEVM&#xff09;ZK rollup 。这一战略合作标志着先进的实时数据索引和部署工具&#xff0c;…

Sora - 探索AI视频模型的无限可能

Sora - 探索AI视频模型的无限可能 随着人工智能技术的飞速发展,AI视频模型已成为科技领域的新热点。而在这个浪潮中,OpenAI推出的首个AI视频模型Sora,以其卓越的性能和前瞻性的技术,引领着AI视频领域的创新发展。让我们将一起探讨Sora的技术特点、应用场景以及对未来创作方…

高级RAG:使用RAGAs + LlamaIndex进行RAG评估,包括原理、图和代码

原文地址&#xff1a;Using RAGAs LlamaIndex for RAG evaluation 2024 年 2 月 5 日 如果您已经为实际的业务系统开发了检索增强生成&#xff08;Retrieval Augmented Generation, RAG&#xff09;应用程序&#xff0c;那么您可能会关心它的有效性。换句话说&#xff0c;您…

【大数据】Flink 内存管理(三):TaskManager 内存分配(理论篇)

Flink 内存管理&#xff08;三&#xff09;&#xff1a;TaskManager 内存分配 1.配置 Total Memory2.配置 Heap and Managed Memory2.1 Task (Operator) Heap Memory2.2 Managed Memory 3.配置 Off-Heap Memory&#xff08;Direct or Native&#xff09;4.详细内存模型5.Framew…

现在学Oracle是49年入国军么?

今天周末&#xff0c;不聊技术&#xff0c;聊聊大家说的最多的一个话题 先说明一下&#xff0c;防止挨喷&#x1f606; 本人并不是职业dba&#xff0c;对数据库就是爱好&#xff0c;偶尔兼职&#xff0c;以下仅个人观点分析&#xff0c;如有不同观点请轻喷&#xff0c;哈哈&…

分享一个我爱工具网源码优化版

应用介绍 本文来自&#xff1a;分享一个我爱工具网源码优化版 - 源码1688 前几天在网上看到了一个不错的工具网源码&#xff0c;但是源码存在一些问题&#xff0c;遂进行了修改优化。 主要修改内容有&#xff1a; 1、后台改为账号密码登录&#xff0c;上传即用&#xff0c;不…

算法分析-面试1-字符串

文章目录 前言一、分类&#xff1a;看看就行了二、字符串API&#xff1a;创建和初始化&#xff1a;查询操作&#xff1a;比较操作&#xff1a;修改操作&#xff1a;截取操作&#xff1a;分割操作&#xff1a;格式化操作&#xff1a;连接操作&#xff08;Java 8 及以后&#xff…

pclpy KD-Tree半径最近邻搜索

pclpy 半径最近邻搜索 一、算法原理1.KD-Tree 介绍2.原理 二、代码三、结果1.原点云2.半径最近邻搜索的点云 四、相关数据 一、算法原理 1.KD-Tree 介绍 kd 树或 k 维树是计算机科学中使用的一种数据结构&#xff0c;用于在具有 k 维的空间中组织一定数量的点。它是一个二叉搜…

Windows下VTK 源码编译(For Qt PCL)

虽然我们在windows下安装PCL的时候就已经安装了VTK&#xff0c;由于跟着PCL安装的VTK是没有和QT联合编译的&#xff0c;所以在使用PCL和QT做点云可视化界面的时候是无法使用QT的插件QVTKWidget。 VTK 源码下载 Tags VTK / VTK GitLab 我这里的环境是Win10 Visual Studio&…

Qt 设置隐式加载dll路径

在c++中DLL的加载方式有两种,显式加载和隐式加载。 隐式加载 在程序从开始运行时,就会按照系统中一定的搜索路径,寻找动态库,找到就自动加载它,才能成功运行程序,这些步骤,是系统自动完成的。 显示加载 我们对动态库的调用,是在代码中直接使用LoadLibrary,或其他加载函…

ContainerHelpers之二分查找算法详解

目录 前言一、JAVA移位运算符1.1 >> 带符号右移位运算符1.2 >>> 无符号右移位运算符1.3 << 左移位运算符1.4 Java 中没有 <<<1.5 ~取反操作 二、ContainerHelpers二分查找算法总结 前言 安卓SparseArray中多次用到了ContainerHelpers的binarySe…

Android java中包的使用

一.包的使用 为了更好的实现项目中类的管理&#xff0c;提供包的概念。 package语句作为Java源文件的第一条语句&#xff0c;指明该文件中定义的类所在的包。(若缺省该语句&#xff0c;则指定为无名包)。 它的格式为&#xff1a;package 顶层包名.子包名 ; 二.java中主要的包…

Leetcode3039. 进行操作使字符串为空

Every day a Leetcode 题目来源&#xff1a;3039. 进行操作使字符串为空 解法1&#xff1a;哈希 排序 操作的定义&#xff1a;每次操作依次遍历 ‘a’ 到 ‘z’&#xff0c;如果当前字符出现在 s 中&#xff0c;那么删除出现位置最早的该字符&#xff08;如果存在的话&…

【ArcGIS】利用DEM进行水文分析:流向/流量等

利用DEM进行水文分析 ArcGIS实例参考 水文分析通过建立地表水文模型&#xff0c;研究与地表水流相关的各种自然现象&#xff0c;在城市和区域规划、农业及森林、交通道路等许多领域具有广泛的应用。 ArcGIS实例 某流域30m分辨率DEM如下&#xff1a; &#xff08;1&#xff09…

机器学习模型的过拟合与欠拟合

机器学习模型的训练过程中&#xff0c;可能会出现3种情况&#xff1a;模型欠拟合、模型正常拟合与模型过拟合。其中模型欠拟合与模型过拟合都是不好的情况。下面将会从不同的角度介绍如何判断模型属于哪种拟合情况。 &#xff08;1&#xff09;欠拟合与过拟合表现方式 欠拟合…

适配器模式:转换接口,无缝对接不同系统

文章目录 **一、技术背景与应用场景****为什么使用适配器模式&#xff1f;****典型应用场景包括但不限于&#xff1a;** **二、适配器模式定义与结构****三、使用步骤举例****四、优缺点分析****总结** 一、技术背景与应用场景 适配器模式在软件设计中扮演着桥梁角色&#xff…