Katie
Katie

Reputation: 1270

C to C# (Mono) memory mapped files/shared memory in linux

I'm working on an embedded system that aquires about 20 megs of data per second. My lower-level acquisition, control, and processing layer converts most of it into a handful of important values, but it can also be useful for the end user to get a view of a window of the unprocessed data.

I'm working on an ASP.NET front end in C# with mod-mono. I would like the server-side part of the ASP.NET page to be able to easily request the last half-second or so worth of data. The C++ code has real-time constraints, so I can't use message passing to respond - it could easily get bogged down by too many clients or someone quickly refreshing. I would like it to be able to place the data somewhere where any number of C# readers can access it as needed.

I'm picturing an area of shared memory with a rolling buffer of the least 16 or 32MB of data. The C++ code is constantly updating it, and the C# code can peek at it whenever it wants to. Is there a way to handle this? All the information I find on using memory-mapped files seems to focus on forking a child, rather than having two unrelated processes use it for IPC - does it have to hit the disk (or fs cache, etc) before the C# application can see it, or does memory mapping from the two programs actually make them share the same pages?

Is there a way of accessing POSIX shared memory objects in C#?

Upvotes: 4

Views: 6956

Answers (1)

Gooseman
Gooseman

Reputation: 2231

Here, an example with C program and C# program sharing information (two different processes) by means of a memory-mapped file:

  1. From console create file: dd if=/dev/zero of=/tmp/sharedfile bs=12288 count=1

  2. The C# program:

    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. The C program:

    #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;
    }
    

Upvotes: 9

Related Questions