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

linux中的C到C#(Mono)内存映射文件/共享内存,c#,c++,linux,mono,shared-memory,C#,C++,Linux,Mono,Shared Memory,我正在开发一个嵌入式系统,每秒可以获取20兆的数据。我的较低级别的采集、控制和处理层将其中的大部分转换为一些重要值,但它也有助于最终用户查看未处理数据的窗口 我正在用C#和mod mono开发一个ASP.NET前端。我希望ASP.NET页面的服务器端部分能够轻松请求最后半秒左右的数据。C++代码有实时的限制,所以我不能使用消息传递来响应——它可能很容易被太多的客户或某人快速刷新而陷入困境。我希望它能够将数据放在任何数量的C#Reader都可以根据需要访问的地方 我正在描绘一个共享内存区域,其中包

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

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

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


是否有办法访问C#?

中的POSIX共享内存对象这里是一个通过内存映射文件访问C程序和C#程序共享信息(两个不同进程)的示例:

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

  • C#计划:

  • 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 ();
                         }
                    }
                }
            }
        }
    }
    
    #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;
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    int main(int argc,char*argv[])
    {
    int-fd;
    整数指数;
    字符*数据;
    const char*filepath=“/tmp/sharedfile”;
    如果((fd=open(filepath,O|u create | O|u RDWR,(mode_t)00700))=-1){
    佩罗(“公开”);
    退出(退出失败);
    }
    数据=mmap(空,12288,保护写入,保护读取,映射共享,fd,0);
    如果(数据==映射_失败){
    佩罗尔(“mmap”);
    退出(退出失败);
    }
    对于(索引=0;索引<200;索引++){
    数据[索引]=“G”;
    } 
    睡眠(10);
    //我们必须在内存映射文件的开头看到“Goose”。
    对于(索引=0;索引<200;索引++){
    fprintf(标准输出,“%c”,数据[索引]);
    }
    对于(索引=0;索引<200;索引++){
    数据[索引]=“H”;
    }
    如果(msync(数据,12288,MS_SYNC)=-1){
    perror(“错误同步到磁盘”);
    } 
    if(munmap(数据,12288)=-1){
    关闭(fd);
    perror(“错误未映射”);
    退出(退出失败);
    }
    关闭(fd);
    返回0;
    }
    

  • 内存映射似乎是传递数据的正确方向。据我所知,对于IPC通信,您仍然需要告诉“ok,get updated view now”(立即调用),可以是命名互斥或简单轮询。还有。@Sinatr我只是在做简单的轮询-我知道只要系统打开,数据就会被读取供我查看。我更关心的是内存映射文件是否能在Mono和C之间正常工作。我担心它看起来会正常工作,但实际上会依赖文件系统/磁盘,而不是两个进程在内存中映射同一页。这在POSIX描述中,请参阅。感谢您提供的示例-您是否知道Mono的MemoryMappedFile.CreateFromFile是否可以与使用shm_open而不是open创建的对象一起使用?我希望它会,但还没有找到任何文档-当我有机会回到项目的这一部分时,我会自己尝试一下。我对使用shm_open感兴趣,因为我真的不需要它来访问磁盘,而且每当系统打开时,缓冲区都会不断更新,因此如果磁盘是文件备份的,它会不断写入磁盘。只是一个提示:字节不能是-1。它可以包含0..255之间的值。如果它是有符号字节,那么它可以保存-128到+128。这是:var data=stream.ReadByte();而(数据!=-1)不会work@JonLennartAasenden当到达流的末尾时,您会得到-1的值。我注意到变量被定义为“var”,本质上与变量相同。它将根据您指定的值进行调整。如果它是一个固定字节字段,那么-1将不适合,您将得到一个超出范围的异常。例如:UByte value=stream.readByte(1);这里-1的值只有在“value”是有符号字节时才有效,否则只有0到255之间的值才有效。但由于它是一个非类型化的变量,任何值都可以存储在其中。@Jon:var不是非类型化的,stream.ReadByte()不返回字节,而是返回int,这就是为什么-1是一个有效的结果。