如何在.NET中使用互锁操作来处理内存映射文件

10

有没有办法在内存映射文件中使用 Interlocked.CompareExchange();Interlocked.Increment(); 方法?

我想实现一个多线程服务,将其数据存储在内存映射文件中,但由于它是多线程的,我需要防止冲突写入,因此我想使用Interlocked操作而不是使用显式锁。

我知道这在本机代码中是可能的,但在.NET 4.0上的托管代码中是否可以实现?


也在寻找这个。你找到解决方案了吗? - TravisWhidden
2个回答

7

好的,这就是做法!我们必须想出解决方法,我想我们可以回馈给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)); 
    }
}

这是有效的,而且可以在多个进程中工作!总是喜欢一个好的挑战!


你知道x64的适当解决方案是什么吗?因为在64位版本的kernel32.dll中,interlocked函数没有被导出。 - Jan
我没有为x64提供解决方案,但是几个月前我们在针对64位操作系统的AnyCPU时遇到了这个问题。欢迎任何想法! - TravisWhidden
你为什么没有使用 .Net Interlocked.Increment 呢? - dan-gph
因为我们正在处理指针,而不是 .net Int32 -- 所以我们必须使用 ptr + offset 来增加内存映射文件中的值。 - TravisWhidden

3
TravisWhidden,你可以像dan-gph说的那样使用Interlocked.Increment静态方法,只需小心指针转换和运算符优先级,以及括号使用...

你将把一个内存指针(加上所需的偏移量)转换为int变量的指针,然后将该指针用作变量。然后你将必须将其用作变量引用。

下面是您的对应片段,使用.net库而不是外部静态导入。

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)))
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接