На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
> Как проверить наличие массива по ссылке в памяти
    Добрый день всем, проблемка нарисовалась и не могу найти решение. Есть библиотека написанная на С++ в которой несколько потоков получают данные от железа и по колбеку отдают ссылку на массив данных в памяти. Пользовательский интерфейс на шарпе. Я просто подписываюсь на колбек плюсовой библиотеки и через Marshal.Copy копирую данные в массив байт (byte[]). Проблема в том что в момент прерывания потока в плюсовой библиотеке в колбеке на шарповой стороне из-за того что ссылка ссылается на уже уничтоженный объект в памяти, возникает необрабатываемое исключение. Так вот вопрос, как проверить на шарпе есть ли данные по ссылке или нет. Проверка IntPtr BytesArray != IntPtr.Zero не дает результата, ибо ссылка существует, но нет по ней данных. Короче как то так, надеюсь понятно изложил.
      Проверить данные можно через:
      ExpandedWrap disabled
        if (Marshal.ReadIntPtr(bytesArray, 0) != IntPtr.Zero) {
          //...
        }

      нет?
        Нет к сожалению. Теперь на этой проверке

        ExpandedWrap disabled
          System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
          Ну, всегда остается try-catch как план B.
          Попробую найти какую-нибудь тестовую C++ библиотеку для экспериментов.
            Цитата Profi @
            Ну, всегда остается try-catch как план B.
            Попробую найти какую-нибудь тестовую C++ библиотеку для экспериментов.

            try-catch не ловит System.AccessViolationException, в этом то и проблема, это необрабатываемое исключение из неуправляемого кода.
              Цитата Pit-Bul @
              Цитата Profi @
              Ну, всегда остается try-catch как план B.
              Попробую найти какую-нибудь тестовую C++ библиотеку для экспериментов.

              try-catch не ловит System.AccessViolationException, в этом то и проблема, это необрабатываемое исключение из неуправляемого кода.

              До .Net 6 можно - HandleProcessCorruptedStateExceptionsAttribute
              Сообщение отредактировано: Profi -
                Profi, проект на Core6
                  Core 6 нет! После Core 3.1 все пошло в .Net 5 и далее. Но это печально тогда да. Блин, попробую покопаться, но я с Marshal'ингом уже лет шесть не работал.
                    Чтобы избежать этой проблемы, можно использовать синхронизацию доступа к массиву данных в момент передачи ссылки из плюсовой библиотеки в пользовательский интерфейс на C#. Для этого можно использовать мьютексы или другие механизмы синхронизации, которые обеспечат безопасный доступ к данным.

                    Вот пример кода на C#, который использует мьютекс для безопасного доступа к массиву данных из разных потоков:
                    ExpandedWrap disabled
                      using System.Threading;
                      public class DataBuffer
                      {
                          private byte[] _data;
                          private Mutex _mutex;
                       
                          public DataBuffer()
                          {
                              _data = null;
                              _mutex = new Mutex();
                          }
                       
                          public void SetData(byte[] data)
                          {
                              _mutex.WaitOne();
                              _data = data;
                              _mutex.ReleaseMutex();
                          }
                       
                          public byte[] GetData()
                          {
                              byte[] result = null;
                              _mutex.WaitOne();
                              if (_data != null)
                              {
                                  result = new byte[_data.Length];
                                  Array.Copy(_data, result, _data.Length);
                              }
                              _mutex.ReleaseMutex();
                              return result;
                          }
                      }

                    В этом примере класс DataBuffer представляет буфер данных, который может быть доступен из нескольких потоков. Метод SetData() используется для установки данных в буфер, а метод GetData() используется для получения копии данных из буфера. При доступе к буферу используется мьютекс для синхронизации потоков.

                    Вы можете использовать этот класс для хранения ссылки на массив данных, полученных из плюсовой библиотеки, и обеспечения безопасного доступа к этим данным из пользовательского интерфейса на C#. В методе SetData() вы можете устанавливать ссылку на массив данных, полученных из плюсовой библиотеки, а в методе GetData() вы можете получать копию данных из массива, используя мьютекс для синхронизации доступа к массиву данных.
                      Как это поможет, когда массив удалится из памяти библиотекой?
                        Мне кажется, здесь неверно выбран подход к обмену данными.

                        Передавать ссылки на память из одного потока в другой уже само по себе опасно, именно по этой причине "Проверка IntPtr BytesArray != IntPtr.Zero не дает результата, ибо ссылка существует, но нет по ней данных."
                        Решение передать данные через буфер, скопировать их и при закрытии потока источника данные не потеряются.

                        Ещё неясно, есть ли доступ к исходникам библиотеки на С++. Если есть, то можно реализовать вариант и со ссылкой, в момент закрытия библиотеки, сообщать потоку на С# что происходит закрытие и все ссылки обнуляются.
                        Сообщение отредактировано: MaIron -
                          MaIron, на счет мютексов вы правы, но потоки не конкурентные, и вместо мьютексов я использую локи, что немного ускоряет работу потоков (плюсовые библиотеки мои).
                          Цитата MaIron @
                          Передавать ссылки на память из одного потока в другой уже само по себе опасно, именно по этой причине "Проверка IntPtr BytesArray != IntPtr.Zero не дает результата, ибо ссылка существует, но нет по ней данных."
                          Решение передать данные через буфер, скопировать их и при закрытии потока источника данные не потеряются.


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

                          Цитата MaIron @
                          Ещё неясно, есть ли доступ к исходникам библиотеки на С++. Если есть, то можно реализовать вариант и со ссылкой, в момент закрытия библиотеки, сообщать потоку на С# что происходит закрытие и все ссылки обнуляются.


                          тут больше проблема в другом. Шарповая чать знает о том что потоки уже закрыты, но пока по не совсем понятной мне причине калбек срабатывает уже после того как на стороне шарпового GUI приняты все меры, а на плюсовой стороне уже уничтожены все объекты. Есть подозрение что причина в том что GUI медленнее обрабатывает данные чем дают потоки на плюсах, и на стороне шарпа образуется некая очередь, но это только предположение, доказательств и подтверждения подобного поведения не нашел на просторах интернета.

                          Вывод для меня простой. Так как потея данных на стороне GUI не критична, потому что все основные обработки и сохранение данных делается на плюсовой стороне, где подобных проблем нет, а код на шарповой части только для отображения процесса пользователю, нужна защита при приеме данных на шарповой стороне. Но способа проверки наличия данных по ссылке и шарпа я не нашел, надеюсь пока. Сейчас я сделал небольшой костыль на плюсовой стороне, я не уничтожаю объекты при остановке потока, а очищаю их либо при запуске по новой, либо убиваю при деинициализации плюсовой библиотеки. Пока работает, но мне костыль не нравиться, ибо при модификации кода в будущем все может поломаться опять и может потребовать более изощренных костылей.
                          Сообщение отредактировано: Pit-Bul -
                          0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                          0 пользователей:


                          Рейтинг@Mail.ru
                          [ Script execution time: 0,0404 ]   [ 16 queries used ]   [ Generated: 27.04.24, 08:40 GMT ]