Linux 中的 C 到 C# (Mono) 内存映射文件/共享内存

本文关键字:内存 映射 文件 共享 Mono 中的 Linux | 更新日期: 2023-09-27 18:36:49

我正在研究一个嵌入式系统,每秒获取大约20兆的数据。我的较低级别的采集、控制和处理层将大部分值转换为少数重要值,但它也有助于最终用户查看未处理数据的窗口。

我正在使用 mod-mono 在 C# 中开发一个 ASP.NET 前端。我希望 ASP.NET 页面的服务器端部分能够轻松请求最后半秒左右的数据。C++代码具有实时约束,因此我无法使用消息传递来响应 - 它很容易被太多客户端或快速刷新的人陷入困境。我希望它能够将数据放置在任何数量的 C# 读者都可以根据需要访问它的地方。

我正在想象一个共享内存区域,其中包含至少 16 或 32MB 数据的滚动缓冲区。C++代码会不断更新它,C# 代码可以随时查看它。有没有办法解决这个问题?我找到的所有关于使用内存映射文件的信息似乎都集中在分叉子文件上,而不是让两个不相关的进程将其用于 IPC - 它是否必须在 C# 应用程序看到它之前到达磁盘(或 fs 缓存等),或者来自两个程序的内存映射实际上使它们共享相同的页面?

有没有办法在 C# 中访问 POSIX 共享内存对象?

Linux 中的 C 到 C# (Mono) 内存映射文件/共享内存

下面是一个 C 程序和 C# 程序通过内存映射文件共享信息(两个不同进程)的示例:

  1. 从控制台创建文件:dd if=/dev/zero of=/tmp/sharedfile bs=12288 count=1

  2. C# 程序:

    using System;
    using System.IO;
    using System.IO.MemoryMappedFiles;
    using System.Threading;
    namespace FileSharedMemory
    {
        class MainClass
        {
            public static void Main (string[] args)
            {
                using (var mmf = MemoryMappedFile.CreateFromFile("/tmp/sharedfile", FileMode.OpenOrCreate, "/tmp/sharedfile"))
                {
                    using (var stream = mmf.CreateViewStream ()) {
                        // 1. C program, filled memory-mapped file with the 'G' character (200 characters)
                        var data = stream.ReadByte ();
                        while (data != -1)
                        {
                            Console.WriteLine ((char)data);
                            data = stream.ReadByte ();
                         }
                         // 2. We write "Goose" at the beginning of memory-mapped file.
                         stream.Position = 0;
                         var buffer = new byte[] { 0x47, 0x6F, 0x6F, 0x73, 0x65 };
                         stream.Write (buffer, 0, 5);
                         Thread.Sleep (20000);
                         // 3. C program, filled memory-mapped file with the 'H' character (200 characters)
                         stream.Position = 0;
                         data = stream.ReadByte ();
                         while (data != -1)
                         {
                             Console.WriteLine ((char)data);
                             data = stream.ReadByte ();
                         }
                    }
                }
            }
        }
    }
    
  3. C 程序:

    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <errno.h>
    int main(int argc, char *argv[])
    {
        int fd;
        int index;
        char *data;
        const char *filepath = "/tmp/sharedfile";
        if ((fd = open(filepath, O_CREAT|O_RDWR, (mode_t)00700)) == -1) {
            perror("open");
            exit(EXIT_FAILURE);
        }
        data = mmap(NULL, 12288, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
        if (data == MAP_FAILED) {
            perror("mmap");
            exit(EXIT_FAILURE);
        }
    
        for (index= 0; index < 200; index++) {
            data[index] = 'G';
        } 
        sleep(10);
        // We must see 'Goose' at the beginning of memory-mapped file.
        for (index= 0; index < 200; index++) {
            fprintf(stdout, "%c", data[index]);
        }
        for (index= 0; index < 200; index++) {
            data[index] = 'H';
        }
        if (msync(data, 12288, MS_SYNC) == -1) {
            perror("Error sync to disk");
        } 
        if (munmap(data, 12288) == -1) {
            close(fd);
            perror("Error un-mmapping");
            exit(EXIT_FAILURE);
        }
        close(fd);
        return 0;
    }