Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.133.12.172] |
|
Сообщ.
#1
,
|
|
|
Добрый день всем, проблемка нарисовалась и не могу найти решение. Есть библиотека написанная на С++ в которой несколько потоков получают данные от железа и по колбеку отдают ссылку на массив данных в памяти. Пользовательский интерфейс на шарпе. Я просто подписываюсь на колбек плюсовой библиотеки и через Marshal.Copy копирую данные в массив байт (byte[]). Проблема в том что в момент прерывания потока в плюсовой библиотеке в колбеке на шарповой стороне из-за того что ссылка ссылается на уже уничтоженный объект в памяти, возникает необрабатываемое исключение. Так вот вопрос, как проверить на шарпе есть ли данные по ссылке или нет. Проверка IntPtr BytesArray != IntPtr.Zero не дает результата, ибо ссылка существует, но нет по ней данных. Короче как то так, надеюсь понятно изложил.
|
Сообщ.
#2
,
|
|
|
Проверить данные можно через:
if (Marshal.ReadIntPtr(bytesArray, 0) != IntPtr.Zero) { //... } нет? |
Сообщ.
#3
,
|
|
|
Нет к сожалению. Теперь на этой проверке
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.' |
Сообщ.
#4
,
|
|
|
Ну, всегда остается try-catch как план B.
Попробую найти какую-нибудь тестовую C++ библиотеку для экспериментов. |
Сообщ.
#5
,
|
|
|
Цитата Profi @ Ну, всегда остается try-catch как план B. Попробую найти какую-нибудь тестовую C++ библиотеку для экспериментов. try-catch не ловит System.AccessViolationException, в этом то и проблема, это необрабатываемое исключение из неуправляемого кода. |
Сообщ.
#6
,
|
|
|
Цитата Pit-Bul @ Цитата Profi @ Ну, всегда остается try-catch как план B. Попробую найти какую-нибудь тестовую C++ библиотеку для экспериментов. try-catch не ловит System.AccessViolationException, в этом то и проблема, это необрабатываемое исключение из неуправляемого кода. До .Net 6 можно - HandleProcessCorruptedStateExceptionsAttribute |
Сообщ.
#7
,
|
|
|
Profi, проект на Core6
|
Сообщ.
#8
,
|
|
|
Core 6 нет! После Core 3.1 все пошло в .Net 5 и далее. Но это печально тогда да. Блин, попробую покопаться, но я с Marshal'ингом уже лет шесть не работал.
|
Сообщ.
#9
,
|
|
|
Чтобы избежать этой проблемы, можно использовать синхронизацию доступа к массиву данных в момент передачи ссылки из плюсовой библиотеки в пользовательский интерфейс на C#. Для этого можно использовать мьютексы или другие механизмы синхронизации, которые обеспечат безопасный доступ к данным.
Вот пример кода на C#, который использует мьютекс для безопасного доступа к массиву данных из разных потоков: 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() вы можете получать копию данных из массива, используя мьютекс для синхронизации доступа к массиву данных. |
Сообщ.
#10
,
|
|
|
Как это поможет, когда массив удалится из памяти библиотекой?
|
Сообщ.
#11
,
|
|
|
Мне кажется, здесь неверно выбран подход к обмену данными.
Передавать ссылки на память из одного потока в другой уже само по себе опасно, именно по этой причине "Проверка IntPtr BytesArray != IntPtr.Zero не дает результата, ибо ссылка существует, но нет по ней данных." Решение передать данные через буфер, скопировать их и при закрытии потока источника данные не потеряются. Ещё неясно, есть ли доступ к исходникам библиотеки на С++. Если есть, то можно реализовать вариант и со ссылкой, в момент закрытия библиотеки, сообщать потоку на С# что происходит закрытие и все ссылки обнуляются. |
Сообщ.
#12
,
|
|
|
MaIron, на счет мютексов вы правы, но потоки не конкурентные, и вместо мьютексов я использую локи, что немного ускоряет работу потоков (плюсовые библиотеки мои).
Цитата MaIron @ Передавать ссылки на память из одного потока в другой уже само по себе опасно, именно по этой причине "Проверка IntPtr BytesArray != IntPtr.Zero не дает результата, ибо ссылка существует, но нет по ней данных." Решение передать данные через буфер, скопировать их и при закрытии потока источника данные не потеряются. передавать объекты из плюсов калбеком я думаю усложнит и усугубит ситуацию, хотя может я и ошибаюсь, но все таки обычно принято передавать в калбеке ссылку. Цитата MaIron @ Ещё неясно, есть ли доступ к исходникам библиотеки на С++. Если есть, то можно реализовать вариант и со ссылкой, в момент закрытия библиотеки, сообщать потоку на С# что происходит закрытие и все ссылки обнуляются. тут больше проблема в другом. Шарповая чать знает о том что потоки уже закрыты, но пока по не совсем понятной мне причине калбек срабатывает уже после того как на стороне шарпового GUI приняты все меры, а на плюсовой стороне уже уничтожены все объекты. Есть подозрение что причина в том что GUI медленнее обрабатывает данные чем дают потоки на плюсах, и на стороне шарпа образуется некая очередь, но это только предположение, доказательств и подтверждения подобного поведения не нашел на просторах интернета. Вывод для меня простой. Так как потея данных на стороне GUI не критична, потому что все основные обработки и сохранение данных делается на плюсовой стороне, где подобных проблем нет, а код на шарповой части только для отображения процесса пользователю, нужна защита при приеме данных на шарповой стороне. Но способа проверки наличия данных по ссылке и шарпа я не нашел, надеюсь пока. Сейчас я сделал небольшой костыль на плюсовой стороне, я не уничтожаю объекты при остановке потока, а очищаю их либо при запуске по новой, либо убиваю при деинициализации плюсовой библиотеки. Пока работает, но мне костыль не нравиться, ибо при модификации кода в будущем все может поломаться опять и может потребовать более изощренных костылей. |