当前位置: 首页 > article >正文

C#与C++交互开发系列(二十):跨进程通信之共享内存(Shared Memory)

在这里插入图片描述

1、前言

共享内存(Shared Memory)是一种高效的跨进程通信方式,尤其适用于同一台计算机上的进程之间的高速数据传输。与套接字相比,共享内存允许多个进程直接访问同一块内存区域,减少了数据传输的中间步骤,适合需要高性能和低延迟的场景。本文将介绍如何在 C# 和 C++ 之间通过共享内存实现跨进程通信,并附上完整的示例代码。

2、什么是共享内存?

共享内存是一种在操作系统中分配的内存区域,允许多个进程对该内存区域进行读写。不同于管道或套接字,数据不需要被复制到缓冲区中进行传输,而是直接由各个进程访问内存数据,从而提高了数据传输效率。

3、实现步骤

  1. C++ 进程:创建共享内存区域,将数据写入内存。
  2. C# 进程:打开该共享内存区域,从内存中读取数据。

4、示例代码

以下代码展示了一个 C++ 进程创建并写入共享内存,另一个 C# 进程读取该共享内存中的数据。

C++ 代码:创建并写入共享内存

使用 Windows API 创建共享内存,并将数据写入共享内存区域。

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

int main() {
    const char* sharedMemoryName = "Local\\MySharedMemory";
    const char* message = "Hello from C++!";

    // 创建共享内存
    HANDLE hMapFile = CreateFileMappingA(
        INVALID_HANDLE_VALUE,
        NULL,
        PAGE_READWRITE,
        0,
        256,
        sharedMemoryName
    );

    if (hMapFile == NULL) {
        std::cerr << "Could not create file mapping object: " << GetLastError() << std::endl;
        return 1;
    }

    // 映射内存
    LPVOID pBuf = MapViewOfFile(
        hMapFile,
        FILE_MAP_ALL_ACCESS,
        0,
        0,
        256
    );

    if (pBuf == NULL) {
        std::cerr << "Could not map view of file: " << GetLastError() << std::endl;
        CloseHandle(hMapFile);
        return 1;
    }

    // 写入数据到共享内存
    CopyMemory((PVOID)pBuf, message, strlen(message) + 1);

    std::cout << "Data written to shared memory: " << message << std::endl;
    std::cout << "Press Enter to exit...";
    std::cin.get();

    // 释放资源
    UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);

    return 0;
}

代码解析

  • CreateFileMappingA:创建共享内存对象。
  • MapViewOfFile:将共享内存映射到进程地址空间。
  • CopyMemory:将数据写入共享内存。
  • UnmapViewOfFileCloseHandle:释放内存映射并关闭句柄。

C# 代码:读取共享内存

在 C# 中使用 MemoryMappedFile 类打开并读取共享内存数据。

using System;
using System.IO.MemoryMappedFiles;
using System.Text;

class Program {
    static void Main() {
        const string sharedMemoryName = "Local\\MySharedMemory";

        // 打开共享内存
        using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting(sharedMemoryName)) {
            // 读取共享内存数据
            using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor(0, 256)) {
                byte[] buffer = new byte[256];
                accessor.ReadArray(0, buffer, 0, buffer.Length);
                
                // 将字节数组转换为字符串
                string message = Encoding.ASCII.GetString(buffer).TrimEnd('\0');
                Console.WriteLine("Data read from shared memory: " + message);
            }
        }
    }
}

代码解析

  • MemoryMappedFile.OpenExisting:打开现有的共享内存对象。
  • MemoryMappedViewAccessor:创建内存视图以读取共享内存中的数据。
  • ReadArray:从共享内存中读取数据。
  • Encoding.ASCII.GetString:将字节数组转换为字符串。

5、运行步骤

  1. 编译并运行 C++ 程序,它将创建共享内存并写入数据。
  2. 运行 C# 程序,它将打开并读取共享内存中的数据。

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

  • C++ 程序输出:Data written to shared memory: Hello from C++!
  • C# 程序输出:Data read from shared memory: Hello from C++!

6、注意事项

  1. 命名空间一致性:确保共享内存名称一致,否则 C# 程序无法找到 C++ 程序创建的共享内存。
  2. 访问权限:共享内存的访问权限应当在 C++ 和 C# 之间保持一致。
  3. 数据格式:在多字节字符的处理上要确保编码一致,以免出现乱码。

7、应用场景

  • 高性能数据传输:适用于大数据量、低延迟的应用场景,如视频处理、游戏引擎等。
  • 跨进程数据共享:允许多个进程同时访问同一块数据,减少数据复制开销。

8、优缺点

  • 优点
    • 高速数据传输,适合大数据量传输场景。
    • 不需要数据序列化与反序列化,降低了性能开销。
  • 缺点
    • 只适用于同一台计算机上的进程通信。
    • 需要注意数据同步,避免多个进程同时写入导致的数据竞争。

9、总结

通过共享内存,C# 和 C++ 程序能够实现高效的跨进程通信,适用于高频、大数据量的数据传输需求。共享内存虽然具备较高的性能优势,但同时需要妥善管理访问权限和数据同步。

在下一篇文章中,我们将介绍 消息队列(Message Queues) 的实现方法,它更适合分布式系统中数据量不大但需要排队处理的场景。


http://www.kler.cn/a/377912.html

相关文章:

  • 【ROS2】话题发布和订阅的频率控制
  • 【C++篇】在秩序与混沌的交响乐中: STL之map容器的哲学探寻
  • CesiumJS 案例 P19:添加矩形、监听鼠标左击、监听鼠标右击、监听鼠标移动
  • 与IP网络规划相关的知识点
  • 0.STM32F1移植到F0的各种经验总结
  • 论文阅读-用于点云分析的自组织网络
  • 论文阅读:Computational Long Exposure Mobile Photography (一)
  • [SICTF Round4] Crypto
  • 简易了解Pytorch中的@ 和 * 运算符(附Demo)
  • 图优化以及如何将信息矩阵添加到残差
  • 网络编程项目之UDP聊天室
  • 【书生.浦语实战营】——入门岛
  • 【OpenSearch】机器学习(Machine Learning)神经搜索教程
  • 【Android】View的事件分发机制
  • Java项目实战II基于Spring Boot的美食烹饪互动平台的设计与实现(开发文档+数据库+源码)
  • 十四届蓝桥杯STEMA考试Python真题试卷第二套第二题
  • 解锁同城流量密码,六大实用技巧全解析
  • 勒索软件通过易受攻击的 Cyber​​Panel 实例攻击网络托管服务器
  • 探索 Spring Boot 中 Elasticsearch 的实战应用
  • Java实战项目-基于 SpringBoot+Vue 的医院管理系统
  • 在Vue中处理图片加载失败:自动替换备用图片
  • kafka实时返回浏览数据
  • 迷宫求解:探索最优路径的算法与应用
  • Java接入Hive
  • IMX6ULL裸机-汇编_反汇编_机器码
  • win10 更新npm 和 node