Linux之IPC通信共享内存(一次拷贝)与消息队列、管道、信号量、socket(两次拷贝)总结(六十二)

news2025/1/4 18:48:38

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

1.前言

本篇目的:理解IPC通信消息队列、管道、socket两次内存拷贝与共享内存一次内存拷贝。

2.IPC通信消息队列、管道、socket、共享内存介绍

  • 在Linux和Android中,进程间通信(IPC)的方式有很多种,包括管道(Pipe)、消息队列(Message Queue)、共享内存(Shared Memory)、信号量(Semaphore)、套接字(Socket)等。其中,管道、消息队列、套接字都需要进行两次内存拷贝,而共享内存只需要一次内存拷贝。

1. 两次内存拷贝的IPC方式:

  • 管道(Pipe): 当一个进程向管道中写入数据时,数据首先会被拷贝到内核缓冲区,然后当另一个进程从管道中读取数据时,数据会从内核缓冲区拷贝到该进程的内存空间。这就是两次内存拷贝。

  • 消息队列(Message Queue): 消息队列的工作方式与管道类似,数据在发送和接收时都需要经过内核缓冲区,因此也需要两次内存拷贝。

  • 套接字(Socket): 套接字在发送和接收数据时,数据也需要经过内核缓冥区,因此也需要两次内存拷贝。

2. 一次内存拷贝的IPC方式:

  • 共享内存(Shared Memory): 共享内存是最快的IPC方式,因为进程是直接对内存进行操作,数据不需要在进程和内核之间进行拷贝。但是,由于多个进程可以同时操作同一块内存,因此需要使用信号量等同步机制来防止数据的不一致。

3.总结

  • 一次内存拷贝:
    一次内存拷贝是指数据在用户空间和内核空间之间只进行了一次拷贝。在Linux和Android中,使用共享内存(shared memory)实现IPC通信是一种一次内存拷贝的方式。共享内存允许多个进程共享同一块物理内存,因此数据被写入内核空间后,其他进程可以直接在内存中读取数据,避免了多次拷贝的开销。

  • 两次内存拷贝:
    两次内存拷贝指数据在用户空间和内核空间之间进行了两次拷贝。在Linux和Android中,使用Socket、管道(pipe)和消息队列(message queue)进行IPC通信会涉及两次内存拷贝。

3.代码实例

1.共享内存进行一次内存拷贝

#include <iostream>
#include <sys/shm.h>
#include <cstring>

int main() {
    key_t key = ftok("/tmp", 'S');
    int shmid = shmget(key, 1024, 0666 | IPC_CREAT);
    char *data = (char*)shmat(shmid, nullptr, 0);

    std::string message = "Hello, IPC using shared memory!";
    std::memcpy(data, message.c_str(), message.size());

    shmdt(data);
    shmctl(shmid, IPC_RMID, nullptr);
    return 0;
}

2.Socket进行两次内存拷贝

// 服务器端
#include <iostream>
#include <sys/socket.h>
#include <cstring>

int main() {
    int server_sock = socket(AF_INET, SOCK_STREAM, 0);
    // 绑定和监听

    int client_sock = accept(server_sock, nullptr, nullptr);

    std::string message = "Hello, IPC using sockets!";
    send(client_sock, message.c_str(), message.size(), 0);

    close(client_sock);
    close(server_sock);

    return 0;
}

// 客户端
#include <iostream>
#include <sys/socket.h>
#include <cstring>

int main() {
    int client_sock = socket(AF_INET, SOCK_STREAM, 0);
    // 连接服务器

    char buffer[1024];
    recv(client_sock, buffer, sizeof(buffer), 0);
    std::cout << "Message received from server: " << buffer << std::endl;

    close(client_sock);

    return 0;
}

3.管道进行两次内存拷贝

#include <iostream>
#include <unistd.h>
#include <cstring>

int main() {
    int pipe_fds[2];

    if (pipe(pipe_fds) == -1) {
        std::cerr << "Failed to create pipe" << std::endl;
        return 1;
    }

    const char* message = "Hello, IPC using pipes!";
    const size_t len = strlen(message);

    if (write(pipe_fds[1], message, len) != static_cast<ssize_t>(len)) {
        std::cerr << "Failed to write to pipe" << std::endl;
        return 1;
    }

    char buffer[64];
    ssize_t bytes_read = read(pipe_fds[0], buffer, sizeof(buffer));
    if (bytes_read == -1) {
        std::cerr << "Failed to read from pipe" << std::endl;
        return 1;
    }

    std::cout << "Message read from pipe: " << std::string(buffer, bytes_read) << std::endl;

    close(pipe_fds[0]);
    close(pipe_fds[1]);

    return 0;
}

4.消息队列进行两次内存拷贝

#include <iostream>
#include <cstring>
#include <sys/msg.h>

struct Message {
    long type;
    char text[100];
};

int main() {
    key_t key = ftok("/tmp", 'Q');
    int msgid = msgget(key, 0666 | IPC_CREAT);

    Message message;
    message.type = 1;
    std::strcpy(message.text, "Hello, IPC using message queues!");

    msgsnd(msgid, &message, sizeof(message.text), 0);

    msgrcv(msgid, &message, sizeof(message.text), 1, 0);
    std::cout << "Message received from message queue: " << message.text << std::endl;

    msgctl(msgid, IPC_RMID, nullptr);

    return 0;
}

5.信号量进行两次内存拷贝

#include <iostream>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstring>

int main() {
    key_t key = ftok("/tmp", 'S');
    int semid = semget(key, 1, IPC_CREAT | 0666);
    if (semid == -1) {
        std::cerr << "Failed to create semaphore" << std::endl;
        return 1;
    }

    sembuf acquire = {0, -1, SEM_UNDO};
    sembuf release = {0, 1, SEM_UNDO};

    if (semop(semid, &acquire, 1) == -1) {
        std::cerr << "Failed to acquire semaphore" << std::endl;
        return 1;
    }

    // Critical section - perform operations that require exclusive access

    std::string message = "Hello, IPC using semaphores!";
    // Perform operations on the shared resource

    if (semop(semid, &release, 1) == -1) {
        std::cerr << "Failed to release semaphore" << std::endl;
        return 1;
    }

    return 0;
}

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

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

相关文章

【蓝桥杯选拔赛真题18】C++病毒繁殖 第十二届蓝桥杯青少年创意编程大赛C++编程选拔赛真题解析

目录 C/C++病毒繁殖 一、题目要求 1、编程实现 2、输入输出 二、算法分析 <

微信小程序入门及开发准备,申请测试号以及小程序开发的两种方式,目录结构说明

目录 1. 介绍 1.1 优点 1.2 开发方式 2. 开发准备 2.1 申请 2.2 申请测试号 2.2 小程序开发的两种方式 2.3 开发工具 3. 开发一个demo 3.1 创建项目 3.2 配置 3.3 常用框架 3.3 目录结构说明 3.4 新建组件 1. 介绍 1.1 优点 是一种不需要下载安装即可使用的应用…

【LeetCode】每日一题 2023_11_12 每日一题 Range 模块

文章目录 刷题前唠嗑题目&#xff1a;Range 模块题目描述代码与解题思路 刷题前唠嗑 LeetCode? 启动&#xff01;&#xff01;&#xff01; 嗯&#xff1f;怎么是 hard&#xff0c;好长&#xff0c;可恶&#xff0c;看不懂&#xff0c;怎么办 题目&#xff1a;Range 模块 题…

邻接矩阵储存图实现深度优先遍历(C++)

目录 基本要求&#xff1a; 图的结构体&#xff1a; 图的构造&#xff1a; 图的深度优先&#xff08;DFS&#xff09;&#xff1a; 图的打印输出&#xff1a; 完整代码&#xff1a; 测试数据&#xff1a; 运行结果&#xff1a; 通过给出的图的顶点和边的信息&#xff0c…

Apache和Nginx实现虚拟主机的3种方式

目录 首先介绍一下Apache和nginx&#xff1a; Nginx和Apache的不同之处&#xff1a; 虚拟主机 准备工作 Apache实现&#xff1a; 方法1&#xff1a;使用不同的ip来实现 方法2&#xff1a;使用相同的ip&#xff0c;不同的端口来实现 方法3&#xff1a;使用相同的ip&…

【C++基础 】类和对象(上)

C基础 类和对象&#xff08;上&#xff09; 1.面向过程和面向对象初步认识2.类的引入3.类的定义4.类的访问限定符及封装4.1 访问限定符4.2 封装 5.类的作用域6.类的实例化7.类对象模型7.1 如何计算类对象的大小7.2 类对象的存储方式猜测7.3 结构体内存对齐规则 8.this指针8.1 t…

人工智能领域200例教程专栏—学习人工智能的指南宝典

&#x1f389;&#x1f38a;&#x1f389; 你的技术旅程将在这里启航&#xff01; &#x1f680; 本专栏&#xff1a;人工智能领域200例教程专栏 从基础到实践&#xff0c;深入学习。无论你是初学者还是经验丰富的老手&#xff0c;对于本专栏案例和项目实践都有参考学习意义。 …

2023 年最新 Alipay 支付包商户接入实现 Java 网站在线支付功能(详细指南教程)

支付宝商户注册申请 若您的材料在电脑端&#xff0c;或企业/单位要求在电脑端操作。您的材料在手机端且方便在支付宝App中管理企业信息&#xff0c;可参阅《手机端开通企业支付宝-操作手册》开通企业支付宝。电脑端准备材料并使用个人支付宝扫码验证身份后开始注册。

二叉树的遍历(先序,中序,后序,层序)

目录 1.先序遍历1.代码实现 2.中序遍历1.代码实现 3.后序遍历1.代码实现 4.遍历算法的应用5.层序遍历1.算法思想2.代码实现 6.由遍历序列构造二叉树 1.先序遍历 根左右。 1.代码实现 若二叉树为空&#xff0c;则什么也不做; 若二叉树非空: ①访问根结点; ②先序遍历左子树; ③先…

Rt-Thread 移植6--多线程(KF32)

6.1 就绪列表 6.1.1 线程就绪优先级组 线程优先级表的索引对应的线程的优先级。 为了快速的找到线程在线程优先级表的插入和移出的位置&#xff0c;RT-Thread专门设计了一个线程就绪优先级组。线程就绪优先组是一个32位的整型数&#xff0c;每一个位对应一个优先级&#xff…

Leetcode—69.x的平方根【简单】

2023每日刷题&#xff08;二十七&#xff09; Leetcode—69.x的平方根 直接法实现代码 int mySqrt(int x) {long long i 0;while(i * i < x) {i;}if(i * i > x) {return i - 1;}return i; }运行结果 二分法实现代码 int mySqrt(int x) {long long left 0, right (l…

数据拟合、参数估计、插值等数据处理算法

介绍 数据拟合&#xff1a; 数据拟合是通过选择或构建合适的函数模型&#xff0c;将给定的数据点与该函数模型进行匹配和拟合的过程。常见的数据拟合方法包括最小二乘法和非线性最小二乘法。最小二乘法通过最小化实际数据与拟合函数的残差平方和来求解最优拟合参数。非线性最小…

文本处理大师:Linux中grep、sed和awk的绝佳教程

1 grep 搜索关键字 全局搜索正则表达式 1.1 基本格式 grep root passwd #过滤含有root关键字-e 多个过滤词 grep -e root -e bash pa grep -E "root|bin" pa # 等同于上面的命令-i 忽略大小写 -E 过滤 grep -E "\<root" passwd ##root字符之前不能有…

中国建设银行转账模拟器,工商农业邮政中国招商假的回执单,易语言轻松实现

用易语言的选择夹画板黑月透明标签编辑框实现了一个假的转账模拟器&#xff0c;当然我还是加了水印的&#xff0c;这个图片你也用不了&#xff0c;只能是学习研究一下源码的实现逻辑&#xff0c;知道画板是怎么对编辑框输入的内容做出反应的&#xff0c;然后是如何获取画板上面…

Leetcode139单词拆分及其多种变体问题

1 声明 1.1 首先&#xff0c;大家常常把这道题当作了背包问题来做&#xff0c;因为其循环结构和背包问题刚好相反&#xff0c;但事实如此嘛&#xff1f; 背包问题通常都是组合问题&#xff0c;这其实是一道“”面向目标值的排列问题“&#xff0c;具体和背包问题有什么不同可…

PyQt制作【小红书图片抓取】神器

文章目录 &#x1f4e2;闲言碎语&#x1f43e;窗口设计&#x1f43e;功能设计&#x1f4da;资源领取 &#x1f4e2;闲言碎语 最近写一个系统&#xff0c;被一个Bug折腾了两天&#xff0c;至今还未解决。由于解决Bug弄得我有点心力憔悴&#xff0c;于是想着写其他小项目玩玩&am…

STM32F407的看门狗

文章目录 看门狗时钟两种看门狗IWDG结构图作用 寄存器IWDG_KR键值寄存器IWDG_PR预分频寄存器2-0 PR预分频器系数 IWDG_RLR重装载寄存器IWDG_SR状态寄存器1RVU 重载值更新0 PVU 预分频值更新注意 写保护超时时间使用步骤取消寄存器 写保护设置预分频系数和重装载值看门狗溢出时间…

2023年第十六届山东省职业院校技能大赛中职组“网络安全”赛项规程

第十六届山东省职业院校技能大赛 中职组“网络安全”赛项规程 一、赛项名称 赛项名称&#xff1a;网络安全 英文名称&#xff1a;Cyber Security 赛项组别&#xff1a;中职组 专业大类&#xff1a;电子与信息大类 二、竞赛目的 网络空间已经成为陆、海、空、天之后的第…

Openlayers:自定义Controls

Openlayers是一款优秀的二维开源地图框架,支持矢量/栅格图层,支持移动端,并且易于自定义和拓展。下面来讲述一下自定义Control的基本思路。 openlayers-features 问题描述 最近在做个人项目时,遇到了一个小问题,就是在地图中心添加一个十字针形状的符号,用来表示地图中心…