How to use interlocked operations against memory-mapped files in .Net
Asked Answered
G

2

10

Is there any way to use the Interlocked.CompareExchange(); and Interlocked.Increment(); methods against values stored in a memory-mapped file?

I'd like to implement a multi-threaded service that will store its data in a memory-mapped file, but since it's multi-threaded I need to prevent conflicting writes, therefore I wonder about the Interlocked operations rather than using explicit locks.

I know it's possible with native code, but can it be done in managed code on .NET 4.0?

Grettagreuze answered 11/10, 2011 at 20:24 Comment(1)
Also looking for this. Did you ever find a solution?Holloman
H
7

OK, this is how you do it! We had to figure this out, and I figured we could give some back to stackoverflow!

class Program
{

    internal static class Win32Stuff
    {
        [DllImport("kernel32.dll", SetLastError = true)]
        unsafe public static extern int InterlockedIncrement(int* lpAddend);
    }

    private static MemoryMappedFile _mmf;
    private static MemoryMappedViewStream _mmvs;

    unsafe static void Main(string[] args)
    {
        const int INT_OFFSET = 8;

        _mmf = MemoryMappedFile.CreateOrOpen("SomeName", 1024);

        // start at offset 8 (just for example)
        _mmvs = _mmf.CreateViewStream(INT_OFFSET, 4); 

        // Gets the pointer to the MMF - we dont have to worry about it moving because its in shared memory
        var ptr = _mmvs.SafeMemoryMappedViewHandle.DangerousGetHandle(); 

        // Its important to add the increment, because even though the view says it starts at an offset of 8, we found its actually the entire memory mapped file
        var result = Win32Stuff.InterlockedIncrement((int*)(ptr + INT_OFFSET)); 
    }
}

This does work, and works across multiple processes! Always enjoy a good challenge!

Holloman answered 24/8, 2012 at 20:54 Comment(4)
Do you know what is the proper solution for x64? As intterlocked functions are not exported from 64bit version of kernel32.dllPicco
I did not come up with a solution for x64, but we did run into that a few months back when targeting AnyCPU with 64bit OS. Any ideas are welcome!Holloman
Why didn't you use the .Net Interlocked.Increment?Magnificat
msdn.microsoft.com/en-us/library/dd78zt0c(v=vs.110).aspx Because we are dealing with a pointer, not a .net Int32 -- so we had to use the ptr + offset to increment the value in the Memory Mapped File.Holloman
F
3

TravisWhidden, actually you can use Interlocked.Increment Static method as dan-gph said, you just have to be careful with pointer casting and operator priority, plus parenthesis usage, in facts...

You'll cast a memory pointer (plus the desired offset), into a pointer to an int variable, then you'll use that pointer as a variable. Then you'll have to use it as a variable reference.

Below you'll find the corresponding snippet of yours using .net library instead of external static import.

P&L

class Program
{
    private static MemoryMappedFile _mmf;
    private static MemoryMappedViewStream _mmvs;

    static void Main(string[] args)
    {
        const int INT_OFFSET = 8;

        _mmf = MemoryMappedFile.CreateOrOpen("SomeName", 1024);
        _mmvs = _mmf.CreateViewStream(INT_OFFSET, 4); 

        unsafe
        {
            IntPtr ptr = _mmvs.SafeMemoryMappedViewHandle.DangerousGetHandle();
            Interlocked.Increment(ref (*((int*)(ptr + INT_OFFSET)))
        }
    }
}
Freemason answered 4/6, 2018 at 10:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.