Reputation: 1270
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
Reputation: 2231
Here, an example with C program and C# program sharing information (two different processes) by means of a memory-mapped file:
From console create file: dd if=/dev/zero of=/tmp/sharedfile bs=12288 count=1
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 ();
}
}
}
}
}
}
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