【Linux】进程间通信_4

news2024/11/27 18:22:37

文章目录

  • 七、进程间通信
    • 1. 进程间通信分类
      • systeam V共享内存
      • 消息队列
      • 信号量
  • 未完待续


七、进程间通信

1. 进程间通信分类

systeam V共享内存

进程间通信的本质就是让不同进程看到同一份资源。而systeam V是通过让不同的进程经过页表映射到同一块内存空间(操作系统完成的)。
在这里插入图片描述
我们申请的共享内存,如果进程结束了,但共享内存并不会释放,需要我们手动释放。管道文件的生命周期是随进程的,但是共享内存的生命周期是随内核的。
使用 ipcs -m 命令可以查看系统中我们创建的共享内存数量。使用 ipcrm -m 和要删除的共享内存的 shmid 即可删除指定共享内存。
在这里插入图片描述
在这里插入图片描述
这里我们来实现一下共享内存模式的进程间通信:
Makefile

.PHONY:all
all:shm_server shm_client

shm_server:ShmServer.cc
	g++ -o $@ $^ -std=c++11
shm_client:ShmClient.cc
	g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
	rm -f shm_server shm_client

Comm.hpp

#pragma once

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

const char* pathname = "/home/student";
const int proj_id = 0x66;
const int defaultsize = 4096;

// 将key转换为16进制
string ToHex(key_t k)
{
    char buffer[1024];
    snprintf(buffer, sizeof(buffer), "0x%x", k);
    return buffer;
}

// 生成共享内存的key
key_t GetShmKeyOrDie()
{
    key_t k = ftok(pathname, proj_id);
    if (k < 0)
    {
        cerr << "ftok error, errno : " << errno << ", errno string : " << strerror(errno) << endl;
        exit(1);
    }
    return k;
}

// 根据key创建共享内存
int CreateShmOrDie(key_t key, int size, int flag)
{
    int shmid = shmget(key, size, flag);
    if (shmid < 0)
    {
        cerr << "shmget error, errno : " << errno << ", errno string : " << strerror(errno) << endl;
        exit(2);
    }
    return shmid;
}

int CreateShm(key_t key, int size)
{
    return CreateShmOrDie(key, size, IPC_CREAT | IPC_EXCL | 0666);
}

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

// 删除共享内存
void DeleteShm(int shmid)
{
    int n = shmctl(shmid, IPC_RMID, nullptr);
    if (n < 0)
    {
        cerr << "shmctl error, errno : " << errno << ", errno string : " << strerror(errno) << endl;
    }
    else
    {
        cout << "shmctl delete shm success, shmid : " << shmid << endl;
    }
}

// 将共享内存附加到进程的地址空间,实现映射关系
void* ShmAttach(int shmid)
{
    void* addr = shmat(shmid, nullptr, 0);
    if (addr == (void*)-1)
    {
        cerr << "shmat error, errno : " << errno << ", errno string : " << strerror(errno) << endl;
        return nullptr;
    }
    return addr;
}

// 解除共享内存的映射关系
void ShmDetach(void* addr)
{
    int n = shmdt(addr);
    if (n < 0)
    {
        cerr << "shmdt error, errno : " << errno << ", errno string : " << strerror(errno) << endl;
    }
}

Fifo.hpp

#ifndef __COMM_HPP__
#define __COMM_HPP__

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

#define Mode 0666
#define Path "./fifo"

// 命名管道类
class Fifo
{
public:
    Fifo(const string& path = Path)
    : _path(path)
    {
        umask(0);
        // 创建命名管道
        int n = mkfifo(_path.c_str(), Mode);
        if (n == 0)
        {
            cout << "mkfifo success" << endl;
        }
        else
        {
            cout << "mkfifo failed, error : " << errno << "errstring : " << strerror(errno) << endl;
        }
    }

    ~Fifo()
    {
        // 删除命名管道
        int n = unlink(_path.c_str());
        if (n == 0)
        {
            cout << "remove " << _path << " success" << endl;
        }
        else
        {
            cout << "remove failed, error : " << errno << "errstring : " << strerror(errno) << endl;
        }
    }
private:
    // 文件路径 + 文件名
    string _path;
};

class Sync
{
public:
    Sync()
    :_rfd(-1)
    ,_wfd(-1)
    {}

    void OpenReadOrDie()
    {
        _rfd = open(Path, O_RDONLY);
        if (_rfd < 0) exit(1);
    }

    void OpenWriteOrDie()
    {
        _wfd = open(Path, O_WRONLY);
        if (_wfd < 0) exit(1);
    }

    bool Wait()
    {
        bool ret = true;
        uint32_t c = 0;
        ssize_t n = read(_rfd, &c, sizeof(uint32_t));
        if (n == sizeof(uint32_t))
        {
            cout << "wait for server" << endl;
        }
        else if (n == 0)
        {
            ret = false;
        }
        else
        {
            return false;
        }
        return ret;
    }

    void WakeUp()
    {
        uint32_t c = 0;
        ssize_t n = write(_wfd, &c, sizeof(uint32_t));
        assert(n == sizeof(uint32_t));
        cout << "wakeup server" << endl;
    }

    ~Sync() {}
private:
    int _rfd;
    int _wfd;
};

#endif

ShmServer

#include "Comm.hpp"
#include "Fifo.hpp"

int main()
{
    // 生成一个key
    key_t key = GetShmKeyOrDie();
    // 生成共享内存
    int shmid = CreateShm(key, defaultsize);
    // 将共享内存和进程进行关联(挂接)
    char *addr = (char*)ShmAttach(shmid);

    // 引入管道
    Fifo fifo;
    Sync syn;
    syn.OpenReadOrDie();

    // 循环读取共享内存
    while(1)
    {
        if (!syn.Wait()) break;
        cout << "Shm content: " << addr << endl;
    }

    // 去关联共享内存
    ShmDetach(addr);
    // 删除共享内存
    DeleteShm(shmid);
    return 0;
}

ShmClient

#include "Comm.hpp"
#include "Fifo.hpp"

int main()
{
    key_t key = GetShmKeyOrDie();
    int shmid = GetShm(key, defaultsize);
    char *addr = (char*)ShmAttach(shmid);

    Sync syn;
    syn.OpenWriteOrDie();

    memset(addr, 0, defaultsize);
    for (int c = 'A'; c <= 'Z'; c++)
    {
        addr[c - 'A'] = c;
        sleep(1);
        syn.WakeUp();
    }

    ShmDetach(addr);
    return 0;
}

结果:
在这里插入图片描述

消息队列

消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法。每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值。IPC资源必须删除,否则不会自动清除,除非重启,所以system V IPC资源的生命周期随内核。
消息队列的本质就是操作系统在内核维护了多个数据块队列,不同进程根据数据怪的标识来通信。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

信号量

信号量本质是一个计数器,描述临界资源数量的计数器。进程访问临界资源本质就是申请信号量,申请成功才能访问临界资源,否者只能等待申请。所有的进程访问临界资源,都需要申请信号量,所有的进程都必须要看到同一个信号量,说明信号量本身就是一个共享资源。
信号量的申请操作称为 P操作 ,释放操作称为 V操作
在命令行使用 ipcs -s 即可查询信号量, ipcrm -s 加信号量标识符 即可删除指定信号量。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


未完待续

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

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

相关文章

强化学习-RLHF-PPO入门

一、定义 强化学习微调分类RM模型 数据集格式训练流程Reward 模型训练流程(分类模型&#xff0c;积极为1&#xff0c;消极为0) AutoModelForSequenceClassificationReward 模型训练案例PPO模型训练流程PPO模型训练案例 二、实现 强化学习微调分类 RLHF:基于人类反馈对语言模型…

深度学习 —— 1.单一神经元

深度学习初级课程 1.单一神经元2.深度神经网络3.随机梯度下降法4.过拟合和欠拟合5.剪枝、批量标准化6.二分类 前言 本套课程仍为 kaggle 课程《Intro to Deep Learning》&#xff0c;仍按之前《机器学习》系列课程模式进行。前一系列《Keras入门教程》内容&#xff0c;与本系列…

eNSP中三层交换机的配置和使用

一、拓扑图 1.新建拓扑图 2.PC端配置 PC1: PC2&#xff1a; 二、基本命令配置 1.S1配置 <Huawei>system-view [Huawei]sysname S1 [S1]vlan 10 //在交换机 S1 上创建 VLAN 10 [S1-vlan10]vlan 20 // 在交换机 S1 上创建 VLAN 20 [S1-vlan20]quit //退出 VLAN 配置…

基于JSP的在线教育资源管理系统

开头语&#xff1a; 你好呀&#xff0c;我是计算机学长猫哥&#xff01;如果你对在线教育资源管理系统感兴趣或者有相关需求&#xff0c;欢迎在文末找到我的联系方式。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;JSP技术 工具&#xff1a;IDE、N…

基于Java仓储出入库管理系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…

代码随想录第34天|贪心算法

59.合并区间 class Solution { public:struct cmp{bool operator()(vector<int>& a, vector<int>& b) {return a[0] < b[0];}};vector<vector<int>> merge(vector<vector<int>>& intervals) {if (intervals.size() 1)retu…

六款顶级原型设计工具推荐,满足你所有需求!

即时设计作为一款专业原型工具&#xff0c;无论是从功能还是插件库配备情况来看&#xff0c;都是毫无疑问可以进行原型图设计的&#xff0c;而且&#xff0c;即时设计内设海量资源库&#xff0c;可以支持大家通过关键词进行搜索相关资源&#xff0c;并且在线编辑使用&#xff0…

Zookeeper:分布式系统中的协调者

Zookeeper&#xff1a;分布式系统中的协调者 前言&#xff1a;引言Zookeeper是什么&#xff1f; 基本概念Zookeeper 数据模型Znode 类型会话Watcher 应用场景分布式锁配置维护组服务名字服务 典型应用场景数据发布/订阅负载均衡命名服务分布式协调/通知集群管理Master选举 工作…

Open3D kitti数据集bin与pcd的相互转换

目录 一、Kitti数据集简介 1.1数据集内容 1.2数据集结构 二、代码实现 2.1bin转pcd 2.2pcd转bin 三、实现效果 一、Kitti数据集简介 KITTI 数据集是由德国卡尔斯鲁厄理工学院&#xff08;KIT&#xff09;和丰田美国技术研究院&#xff08;Toyota Technological Institut…

昇思25天学习打卡营第2天|快速入门

使用MindSpore实现简单的深度学习模型 环境配置 第一步当然是装包&#xff1a; !pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore2.2.14 import mindspore from mindspore import nn from mindspore.dataset import vision, transforms from mindspore.d…

深入了解MySQL的哈希索引

深入了解MySQL的哈希索引 哈希索引是一种基于哈希表的数据结构&#xff0c;通过对索引键值进行哈希运算&#xff0c;直接定位存储位置&#xff0c;从而实现快速数据访问。哈希索引在等值查询中表现尤为出色&#xff0c;但不适用于范围查询。虽然哈希索引在某些场景下可以显著提…

从特斯拉视角,看智能驾驶研究框架

第一章:回顾历史&#xff0c;智能驾驶的核心主线是算法的演进史&#xff0c;从2017年至今在感知侧规控侧实现算法从规则为主走向端到端。算法方面&#xff0c;2017-2022年&#xff0c;特斯拉在感知侧走向端到端&#xff0c;实现BEVTransformerOccupancy。2021-2023年&#xff0…

Python深度学习技术

原文链接&#xff1a;Python深度学习技术 近年来&#xff0c;伴随着以卷积神经网络&#xff08;CNN&#xff09;为代表的深度学习的快速发展&#xff0c;人工智能迈入了第三次发展浪潮&#xff0c;AI技术在各个领域中的应用越来越广泛。Transformer模型&#xff08;BERT、GPT-…

2024年最新中级会计职称考试题库。

46.甲将一汇票背书转让给乙&#xff0c;但该汇票上未记载乙的名称。其后&#xff0c;乙在该汇票被背书人栏内记载了自己的名称。根据《票据法》的规定&#xff0c;下列有关该汇票背书与记载效力的表述中&#xff0c;正确的是&#xff08;&#xff09;。 A.甲的背书无效&#x…

C语言:sprintf与snprintf

C语言提供了强大的格式化输出的接口&#xff0c;可以输出到不同的文件或者字符串等&#xff0c;以sprintf和snprintf为例介绍一下 sprintf 格式化输出到字符串 函数签名 int sprintf(char *str, const char *format, ...);与printf相比就是多了前面的char*参数&#xff0c;…

创新降重工具助力学术写作:提升论文独创性

现在大部分学校已经进入到论文查重降重的阶段了。如果查重率居高不下&#xff0c;延毕的威胁可能就在眼前。对于即将告别校园的学子们&#xff0c;这无疑是个噩梦。四年磨一剑&#xff0c;谁也不想在最后关头功亏一篑。 查重率过高&#xff0c;无非以下两种原因。要么是作为“…

【激光雷达使用记录】—— 如何在ubuntu中利用ros自带的rviz工具实时可视化雷达点云的数据

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、查看雷达数据的 frame_id1. 查看雷达数据的话题2. 查看数据的frame_id 二、可视化雷达数据总结 前言 RViz&#xff08;ROS Visualization&#xff09;是机…

华为面试题及答案——机器学习(二)

21. 如何评价分类模型的优劣? (1)模型性能指标 准确率(Accuracy): 定义:正确分类的样本数与总样本数之比。适用:当各类样本的数量相对均衡时。精确率(Precision): 定义:预测为正类的样本中实际为正类的比例。适用:当关注假阳性错误的成本较高时(例如垃圾邮件检测…

超细毛搭配超宽设计,一款更呵护牙龈的牙刷

牙龈敏感的时候&#xff0c;刷牙特别难受&#xff0c;最近试了试惠百施&#xff08;EBISU&#xff09;65孔宽头软毛牙刷&#xff0c;感觉它的口腔护理体验很不错。这款牙刷的设计独特&#xff0c;采用宽头设计&#xff0c;一次就能刷两排牙齿&#xff0c;极大地提高了清洁效率。…