Question

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?

Était-ce utile?

La solution

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!

Autres conseils

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)))
        }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top