Проблемы с использованием класса MemoryMappedFile в Mono

Я пытаюсь перенести новую версию библиотеки Isis2 из .NET в Windows в Mono/Linux. В этом новом коде используются объекты MemoryMappedFile, и я внезапно столкнулся с проблемами с библиотекой Mono.Posix.Helper. Я считаю, что мои проблемы исчезнут, если я смогу успешно скомпилировать и запустить следующую тестовую программу:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.MemoryMappedFiles;

namespace foobar
{
  class Program
  {
    static int CAPACITY = 100000;
    static void Main(string[] args)
    {
        MemoryMappedFile mmf = MemoryMappedFile.CreateNew("test", CAPACITY);
        MemoryMappedViewAccessor mva = mmf.CreateViewAccessor();
        for (int n = 0; n < CAPACITY; n++)
        {
            byte b = (byte)(n & 0xFF);
            mva.Write<byte>(n, ref b);
        }
    }
  }
}

... в настоящее время, когда я пытаюсь скомпилировать это на Mono, я получаю ошеломляющий набор ошибок компоновщика: кажется, не удается найти libMonoPosixHelper.so, хотя мой LD_LIBRARY_PATH включает каталог, содержащий этот файл, а затем, если мне удастся пройти мимо на этом этапе я получаю «System.NotImplementedException: запрошенная функция не реализована». во время выполнения. Тем не менее, я просмотрел реализацию метода CreateNew в Mono; он кажется полностью реализованным, и то же самое верно для метода CreateViewAccessor. Таким образом, у меня есть ощущение, что что-то идет не так при связывании с библиотеками Mono.

Есть ли у кого-нибудь опыт работы с объектами MemoryMappedFile в Mono? Я вижу довольно много вопросов по этому поводу здесь и на других сайтах, но все они кажутся старыми темами...


person Ken Birman    schedule 14.08.2013    source источник
comment
в этом классе есть некоторые NIE, я думаю, вам нужно реализовать отсутствующую перегрузку или что-то в этом роде (и внести ее обратно в моно)   -  person knocte    schedule 15.08.2013
comment
Knocte, я думаю, что это может быть проблемой. Я проводил простые эксперименты, и мне все больше и больше кажется, что Mono может не иметь правильной реализации случая чистой памяти для MemoryMappedFiles. В .NET у вас может быть файл с отображением памяти без файлов на диске, и люди часто используют это. Но кажется, что в Linux может потребоваться реальный файл (не такая уж большая проблема), и, возможно, Mono просто не обрабатывает этот случай правильно. Кроме того, что-то очень странное в том, как компоновщик обрабатывает эту конкретную DLL, но вы можете обойти эту проблему...   -  person Ken Birman    schedule 15.08.2013
comment
вы ошибаетесь, MemoryMappedFile обычно работает в Linux (реализация очень полная), но, похоже, вы нашли пограничный случай, в котором это не так. Вы должны придумать тестовый пример, который работает в .NET, а не в Linux, и внести исправление, это должно быть легко   -  person knocte    schedule 15.08.2013
comment
Тот, что показан выше, работает в .NET в Windows, а не в Linux. Это моя точка зрения. Попробуй. Вы получите ошибку. Затем попробуйте изменить имя файла на /tmp/test. Вы получите другую ошибку. Фактически, независимо от того, что вы делаете, вы получите сообщение об ошибке в Linux, и независимо от того, что вы делаете, версия для Windows работает успешно (и правильно; это короткий пример чего-то гораздо более сложного, с чем я сейчас работаю в Isis2). окна)   -  person Ken Birman    schedule 15.08.2013
comment
правильно, тогда это крайний случай, поработайте с ним, чтобы найти правильное исправление для моно   -  person knocte    schedule 15.08.2013


Ответы (1)


Хорошо, я понял, по крайней мере, часть этого, проверив код Mono, реализующий этот API. На самом деле они реализовали CreateNew таким образом, который довольно сильно отличается от .NET API, в результате чего эти методы ведут себя совсем не так, как вы ожидаете.

Для CreateNew они на самом деле требуют, чтобы имя файла, которое вы укажете, было именем существующего файла Linux, размер которого, по крайней мере, не меньше указанной вами емкости, а также выполняли некоторые другие проверки разрешений на доступ (конечно), исключительный доступ (который противоречит совместному использованию...) и убедиться, что запрошенная вами емкость > 0. Поэтому, если файл был открыт ранее или кто-то другой, это не удастся - в отличие от .NET, где вы явно используете файлы с отображением памяти для совместного использования.

Напротив, CreateOrOpen кажется «более или менее» правильно реализованным; переход на эту версию, кажется, решает проблему. Чтобы получить эффект CreateNew, сначала выполните Delete, обернув его в try/catch, чтобы поймать IOException, если файл не существует. Затем используйте File.WriteAllBytes, чтобы создать файл с желаемым содержимым. Затем вызовите CreateOrOpen. Сейчас это звучит глупо, но это работает. Очевидно, что вы не можете гарантировать атомарность таким образом (три операции вместо одной), но, по крайней мере, вы получаете желаемую функциональность.

Я могу жить с этими ограничениями, пока они работают, но они могут удивить других и полностью отличаются от определения .NET API для MemoryMappedFile.

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

person Ken Birman    schedule 15.08.2013
comment
отличный анализ! учитывая, что вы много знаете об этом, вы были бы идеальным человеком, чтобы внести исправление в исходный монокод. - person knocte; 20.08.2013
comment
Я смотрел на это - теперь у меня проблемы с асинхронной отправкой Mono (BeginSendTo). Исправление этого материала может быть правильным решением. Странно то, что качество кода на самом деле выглядит очень высоким, поэтому вызывает удивление тот факт, что CreateNew не был отлажен (на самом деле, даже CreateOrOpen не полностью отлажен). С другой стороны, этот конкретный модуль полон [Mono ToDo] и выдает строки NotImplemented. Может быть, я просто на грани кровотечения... - person Ken Birman; 21.08.2013
comment
Качество кода Mono очень высокое. Единственная проблема заключается в том, что у них ограниченные ресурсы, и вы не можете ожидать, что они правильно реализуют каждый крайний случай. Вы можете сделать git blame, чтобы узнать, когда и кто его разработал... тогда, с этим ником, вы, вероятно, сможете общаться с разработчиком в irc://irc.gnome.org/mono. - person knocte; 21.08.2013