The following code produces a stack overflow error. It creates a shared memory space and then attempts to copy the shared memory contents to a local buffer. I have written several programs to do this in unmanaged C++, but C# is foreign to me... I have allocated a buffer on the heap and am attempting to copy the shared memory buffer into my local buffer. This is where the stack overflow error triggers: accessor.Read<my_struct>(0, out ps.hi);. Perhaps the accessor.Read function attempts to create a local copy of the shared memory buffer before copying it into the reference I provide it? If so, what is the recommended way to transfer large memory chunks to and from shared memory in C#? I have not found this issue in my internet searches so any help would be appreciated...
The exact error message reads: "An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Threading;
namespace ConsoleApplication2
{
unsafe struct my_struct
{
public fixed UInt16 img[1280 * 960];
}
class Program
{
my_struct hi;
static void Main(string[] args)
{
Program ps = new Program();
ps.hi = new my_struct();
using (var mmf = MemoryMappedFile.CreateOrOpen("OL_SharedMemSpace", System.Runtime.InteropServices.Marshal.SizeOf(ps.hi)))
{
using (var accessor = mmf.CreateViewAccessor())
{
//Listen to event...
EventWaitHandle request_event;
EventWaitHandle ready_event;
try
{
request_event = EventWaitHandle.OpenExisting("OL_ReceiveEvent");
}
catch (WaitHandleCannotBeOpenedException)
{
Console.WriteLine("Receive event does not exist...creating one.");
request_event = new EventWaitHandle(false, EventResetMode.AutoReset, "OL_ReceiveEvent");
}
try
{
ready_event = EventWaitHandle.OpenExisting("OL_ReadyEvent");
}
catch (WaitHandleCannotBeOpenedException)
{
Console.WriteLine("Ready event does not exist...creating one.");
ready_event = new EventWaitHandle(false, EventResetMode.AutoReset, "OL_ReceiveEvent");
}
System.Console.WriteLine("Ok...ready for commands...");
while (true)
{
accessor.Read<my_struct>(0, out ps.hi);
request_event.WaitOne();
}
}
}
}
}
}
Maybe it can be helpful. Here is C++ native writer:
#include <windows.h>
#include <memory>
const int BUFFER_SiZE = sizeof(uint8_t) * 1024 * 1024;
const wchar_t MMF_NAME[] = L"Global\\SharedMemoryExample";
int main()
{
wprintf(L"Shared Memory example. Native writer\r\n");
wprintf(L"BUFFER_SIZE: %d bytes\r\n", BUFFER_SiZE);
wprintf(L"MMF name: %s\r\n", MMF_NAME);
HANDLE hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, BUFFER_SiZE, MMF_NAME);
if (hMapFile == NULL)
{
wprintf(L"CreateFileMapping failed with error: %d", GetLastError());
return -1;
}
std::shared_ptr<void> mapHandleGuard(hMapFile, &::CloseHandle);
uint8_t* pBuffer = (uint8_t*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, BUFFER_SiZE);
if (pBuffer == NULL)
{
wprintf(L"MapViewOfFile failed with error: %d", GetLastError());
return -2;
}
std::shared_ptr<void> bufferGuard(pBuffer, &::UnmapViewOfFile);
wprintf(L"Press 'Enter' to write some data to shared memory");
getchar();
// Write magic data :)
memset(pBuffer, 0xFA, BUFFER_SiZE);
wprintf(L"Press 'Enter' close application");
getchar();
return 0;
}
And here is .NET reader:
class Program
{
private const string MMF_NAME = "Global\\SharedMemoryExample";
const int BUFFER_SIZE = sizeof(byte) * 1024 * 1024;
static void Main(string[] args)
{
try
{
Console.WriteLine("Shared Memory example. .NET reader");
Console.WriteLine("BUFFER_SIZE: {0} bytes", BUFFER_SIZE);
Console.WriteLine("MMF name: {0}", MMF_NAME);
Console.WriteLine("Press 'Enter' to open Shared memory");
Console.ReadLine();
using (var mmf = System.IO.MemoryMappedFiles.MemoryMappedFile.OpenExisting(MMF_NAME))
{
Console.WriteLine("{0} was opened.", MMF_NAME);
using (var accessor = mmf.CreateViewAccessor())
{
Console.WriteLine("ViewAccessor was created.");
byte[] buffer = new byte[BUFFER_SIZE];
Console.WriteLine("Press 'Enter' to read from Shared memory");
Console.ReadLine();
int cntRead = accessor.ReadArray(0, buffer, 0, BUFFER_SIZE);
Console.WriteLine("Read {0} bytes", cntRead);
if (IsBufferOk(buffer, cntRead))
Console.WriteLine("Buffer is ok");
else
Console.WriteLine("Buffer is bad!");
}
}
}
catch(Exception ex)
{
Console.WriteLine("Got exception: {0}", ex);
Console.ReadLine();
}
}
private static bool IsBufferOk(byte[] buffer, int length)
{
for(int i = 0; i < length; i++)
{
if (buffer[i] != 0XFA)
return false;
}
return true;
}
}
For simplifying I used console input for synchronization. Also if your OS >= Windows Vista, you should run these apps under elevated command prompt.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With