Как использовать блокированные операции с отображенными в память файлами в .Net - PullRequest
8 голосов
/ 12 октября 2011

Можно ли использовать методы Interlocked.CompareExchange(); и Interlocked.Increment(); для значений, хранящихся в отображенном в памяти файле?

Я бы хотел реализовать многопоточный сервис, который будет хранить свои данные в файле с отображением в памяти, но, поскольку он многопоточный, мне нужно предотвращать конфликтующие записи, поэтому мне интересны операции Interlocked, а не использование явных замки.

Я знаю, что это возможно с собственным кодом, но можно ли это сделать в управляемом коде в .NET 4.0?

Ответы [ 2 ]

6 голосов
/ 25 августа 2012

ОК, вот как ты это делаешь! Мы должны были это выяснить, и я решил, что мы могли бы вернуть стековый поток!

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

Это работает и работает в нескольких процессах! Всегда наслаждайтесь хорошим испытанием!

2 голосов
/ 04 июня 2018

TravisWhidden , на самом деле вы можете использовать метод Interlocked.Increment Static, так как dan-gph говорит, что вам просто нужно быть осторожным с приведением указателя и приоритетом оператора, а также с использованием скобок вфакты ...

Вы приведете указатель памяти (плюс желаемое смещение) в указатель на переменную 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)))
        }
    }
}
...