Как использовать взаимосвязанные операции с файлами, отображаемыми в память, в .Net

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

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

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


person Mike Schenk    schedule 11.10.2011    source источник
comment
Тоже ищу это. Вы когда-нибудь находили решение?   -  person TravisWhidden    schedule 23.08.2012
comment
Написал ответ ниже. Пожалуйста примите!!! :) Спасибо.   -  person TravisWhidden    schedule 25.08.2012


Ответы (2)


Хорошо, вот как вы это делаете! Мы должны были это выяснить, и я подумал, что мы могли бы вернуть часть 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)); 
    }
}

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

person TravisWhidden    schedule 24.08.2012
comment
Знаете ли вы, что является правильным решением для x64? Поскольку заблокированные функции не экспортируются из 64-битной версии kernel32.dll - person Jan; 23.09.2014
comment
Я не придумал решения для x64, но мы столкнулись с ним несколько месяцев назад, когда нацеливались на AnyCPU с 64-битной ОС. Любые идеи приветствуются! - person TravisWhidden; 24.09.2014
comment
Почему вы не использовали .Net Interlocked.Increment? - person dan-gph; 25.01.2017
comment
msdn.microsoft.com/en-us/library /dd78zt0c(v=vs.110).aspx Поскольку мы имеем дело с указателем, а не с .net Int32, нам пришлось использовать смещение ptr + для увеличения значения в файле отображения памяти. - person TravisWhidden; 25.01.2017

TravisWhidden, на самом деле вы можете использовать статический метод Interlocked.Increment как 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)))
        }
    }
}
person sinsalabim    schedule 04.06.2018