C++/C# 互操作中的内存映射和 P/Invoke 性能

Posted

技术标签:

【中文标题】C++/C# 互操作中的内存映射和 P/Invoke 性能【英文标题】:Memory mapping and P/Invoke performance in C++/C# interop 【发布时间】:2016-12-09 18:49:26 【问题描述】:

不久前我开发了一些 dll,以便 P/Invoke 从 C++ dll 到 C# 的一些东西。但是,我在硬实时环境中工作,P/Invoke 被证明太慢而无法执行某些操作。

所以我发现内存映射是一种(据说)更快的 P/Invoke 替代方案,并且在我的测试期间,C++ 方面看起来并不太简陋:

#include "stdafx.h"

#define BUF_SIZE 256
TCHAR szName[] = TEXT("MyFileMappingObject");
char* pcTest = "Message from C++";

int _tmain()

    HANDLE hMapFile;
    LPCTSTR pBuf;

    hMapFile = CreateFileMapping(
                INVALID_HANDLE_VALUE,
                NULL,
                PAGE_READWRITE,
                0,
                BUF_SIZE,
                szName);

    if (hMapFile == NULL) 
        _tprintf(TEXT("Could not create file mapping object (%d).\n"), GetLastError());
        return 1;
    

    pBuf = (LPTSTR)MapViewOfFile(
                hMapFile,
                FILE_MAP_ALL_ACCESS,
                0,
                0,
                BUF_SIZE);

    if (pBuf == NULL) 
        _tprintf(TEXT("Could not map view of file (%d).\n"), GetLastError());
        CloseHandle(hMapFile);
        return 1;
    

    CopyMemory((PVOID)pBuf, pcTest, (strlen(pcTest) * sizeof(char*)));

    std::cin.get(); 

    UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);

    return 0;

我从这里改编了代码:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa366551(v=vs.85).aspx

这里是 C# 方面:

    static void Main(string[] args)
    
        MemoryMappedFile pagedMemoryMap = MemoryMappedFile.OpenExisting("MyFileMappingObject", MemoryMappedFileRights.FullControl);

        using (MemoryMappedViewAccessor fileMap = pagedMemoryMap.CreateViewAccessor())
        
            var array = new byte[256];
            fileMap.ReadArray(0, array, 0, 16); //Take notice on this line
            var text = Encoding.ASCII.GetString(array);
            Console.WriteLine(text);
        

        Console.ReadKey();
    

它按预期工作,但这里有一个问题:ReadArray 方法中字节数组长度的固定大小。我想我必须将实际应用程序中实际字符串的长度写入不同的共享,然后用它来读取字符串值,但这似乎太麻烦了。考虑到我在实际应用程序中从 C++ 中实际读取的是结构数组(大部分仅包含字符串),我是否会从内存映射中获得任何收益,性能方面?我没有任何用可能没有预期结果的替代方案来膨胀稳定代码(尽管速度很慢)的意图,那么这种方法有什么真正的好处吗?有更好的选择吗?

【问题讨论】:

C# 不适合硬实时环境。垃圾收集器会错过你的时间。事实上,Windows 不适合硬实时环境,因为分页和中断处理会错过您的时间。软实时/接近实时是另一回事。 当然,我们不打算采用 1:1 的比例。 C# 部分仅用于可视化,并且值会不断快速地更新,即使我们错过了更高级别的一些更新也没关系。然而,使用软实时仿真器运行一切都很好,但是一旦我们连接到真正的硬件,事情就会变得很糟糕 【参考方案1】:

内存映射文件非常适合跨进程共享数据。它们对于在同一内存空间中的模块之间共享毫无意义。

只需以普通方式将您的数据结构定义为引用类类型,然后将其固定。现在 C++ 可以直接使用普通的指针访问来访问数据结构了。

计数字符串在固定数组中与在内存映射文件中一样有效,但您不需要任何内核调用来设置它们。

【讨论】:

我喜欢你关于固定对象的建议。我会在星期一尝试并报告结果 今天是星期一吗? @GregM 离星期一还有几个不喜欢的地方 :)

以上是关于C++/C# 互操作中的内存映射和 P/Invoke 性能的主要内容,如果未能解决你的问题,请参考以下文章

互操作 C++ 时释放分配的内存

c程序内存模型

c语言 内存,可执行文件

语言互操作性中的套接字编程

语言互操作性中的套接字编程

Fortran 和 c 互操作性