SafeHandle и блокирующие операции
От: DiRTy GaRRy  
Дата: 04.11.10 11:25
Оценка:
Привет всем.

Во время реализации обёртки для некой внешней нэтивной библиотеки я столкнулся с проблемами связанными с SafeHandle.

Итак:
  1. Имеется некая нэтивная библиотека, которая реализует сетевую работу с DICOM (медицинский стандарт).
  2. При написании обёртки сделан свой SafeHandle для сущности отвечающей за сетевое взаимодействие (далее MSM). При работе с этой MSM есть блокирующие операции, например, операция ожидания входящего соединения, так же есть просто длительные операции. Соответственно оно крутится в отдельном потоке.
  3. Для того что бы блокирующая операция завершилась необходимо вызвать метод по уничтожению MSM, который, собственно, завёрнут в SafeHandle.ReleaseHandle.

Проблема, заключается в том, что если в данный момент для MSM активна блокирующая или длительная операция, то при вызове SafeHandle.Dispose (вызов происходит из другого потока, конечно) до вызова ReleaseHandle, в первом случае, дело не доходит никогда, а во втором, оно вызывается только по завершении длительной операции. Сейчас я борюсь с этим передавая в такие функции IntPtr из DangerousGetHandle, но как то это, IMHO, не правильно.

Вопрос, как мне избавиться от IntPtr и использовать везде SafeHandle? Или я чего то не понимаю?
Ы?
Re: SafeHandle и блокирующие операции
От: Jolly Roger  
Дата: 04.11.10 12:51
Оценка:
Здравствуйте, DiRTy GaRRy, Вы писали:

DG>Проблема, заключается в том, что если в данный момент для MSM активна блокирующая или длительная операция, то при вызове SafeHandle.Dispose (вызов происходит из другого потока, конечно) до вызова ReleaseHandle, в первом случае, дело не доходит никогда, а во втором, оно вызывается только по завершении длительной операции.


Дело видимо в том, что рантайм автоматически увеличивает внутренний счётчик при передаче потомка SafeHadle в нативный код, как раз для предотвращения его преждевременного закрытия. Если Вы уверены, что для Вашего случая SafeHandle подходит наилучшим образом, то можно, во-первых, вызывать вручную DangerousRelease. Во-вторых, метод Dispose(bool) — виртуальный, Вы его можете переписать так, как Вам надо. И в третьих, можно добавить свой, специфичный для Вашего случая, метод, который будет выполнять закрытие хёндла. Не забывайте только при этом его инвалидировать.
"Нормальные герои всегда идут в обход!"
Re[2]: SafeHandle и блокирующие операции
От: DiRTy GaRRy  
Дата: 04.11.10 13:29
Оценка:
Здравствуйте, Jolly Roger, Вы писали:

JR>Здравствуйте, DiRTy GaRRy, Вы писали:


DG>>Проблема, заключается в том, что если в данный момент для MSM активна блокирующая или длительная операция, то при вызове SafeHandle.Dispose (вызов происходит из другого потока, конечно) до вызова ReleaseHandle, в первом случае, дело не доходит никогда, а во втором, оно вызывается только по завершении длительной операции.


JR>Дело видимо в том, что рантайм автоматически увеличивает внутренний счётчик при передаче потомка SafeHadle в нативный код, как раз для предотвращения его преждевременного закрытия. Если Вы уверены, что для Вашего случая SafeHandle подходит наилучшим образом, то можно, во-первых, вызывать вручную DangerousRelease. Во-вторых, метод Dispose(bool) — виртуальный, Вы его можете переписать так, как Вам надо. И в третьих, можно добавить свой, специфичный для Вашего случая, метод, который будет выполнять закрытие хёндла. Не забывайте только при этом его инвалидировать.


Ну я, в принципе, про некий счётчик тоже догадывался. Если же далать через всяческие дополнительные методы, то тут получается, что SafeHandle и не нужен, так как проще реализовать IDisposable и не париться. Мне просто хотелось сделать работу с unmanaged ресурсами, как это рекомендует MS, но по ходу дела не получится.
Ы?
Re[3]: SafeHandle и блокирующие операции
От: Jolly Roger  
Дата: 04.11.10 13:45
Оценка:
Здравствуйте, DiRTy GaRRy, Вы писали:

DG>Ну я, в принципе, про некий счётчик тоже догадывался. Если же далать через всяческие дополнительные методы, то тут получается, что SafeHandle и не нужен, так как проще реализовать IDisposable и не париться. Мне просто хотелось сделать работу с unmanaged ресурсами, как это рекомендует MS, но по ходу дела не получится.


SafeHandle наследует от CriticalFinalizerObject, для которого рантайм даёт дополнительные гарантии по освобождению, кроме того автоматически предоставляется конвертация в IntPtr и обратно при вызове нативных методов. Разумеется, волшебства нет, и не вполне стандартное поведение придётся реализовывать самостоятельно. Ну а если вышеперечисленное не нужно, то конечно, можно и не париться, хотя я не вижу, чем свой объект, реализующий IDisposable, будет сколь-нибудь заметно проще
"Нормальные герои всегда идут в обход!"
Re[3]: SafeHandle и блокирующие операции
От: TK Лес кывт.рф
Дата: 04.11.10 18:04
Оценка:
Здравствуйте, DiRTy GaRRy, Вы писали:

DG>Ну я, в принципе, про некий счётчик тоже догадывался. Если же далать через всяческие дополнительные методы, то тут получается, что SafeHandle и не нужен, так как проще реализовать IDisposable и не париться. Мне просто хотелось сделать работу с unmanaged ресурсами, как это рекомендует MS, но по ходу дела не получится.


SafeHandle отвечает за освобождение используемого Handle в случае если произодет исключение при маршаллинге результата. Без этого есть возможность что, вновь полученный handle будет просто потерян.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re: SafeHandle и блокирующие операции
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 06.06.11 08:54
Оценка:
Здравствуйте, DiRTy GaRRy, Вы писали:

DG>Итак:

DG>

    DG>
  1. Имеется некая нэтивная библиотека, которая реализует сетевую работу с DICOM (медицинский стандарт).
    DG>
  2. При написании обёртки сделан свой SafeHandle для сущности отвечающей за сетевое взаимодействие (далее MSM). При работе с этой MSM есть блокирующие операции, например, операция ожидания входящего соединения, так же есть просто длительные операции. Соответственно оно крутится в отдельном потоке.
    DG>
  3. Для того что бы блокирующая операция завершилась необходимо вызвать метод по уничтожению MSM, который, собственно, завёрнут в SafeHandle.ReleaseHandle.
    DG>

Извините, что поднимаю эту древнюю тему. Насколько я понял, проблема в том что
— один поток юзает ресурс
— второй поток пытается этот ресурс убить
— .NET второму потоку не позволяет такое делать

Ну дык, полагаю, .NET тут прав на все 100%. И здесь нужно менять принцип прерывания работы с этим ресурсом. Или нет?
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[2]: SafeHandle и блокирующие операции
От: Igor Vyatkin  
Дата: 06.06.11 09:27
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

[Skip]

КД>Извините, что поднимаю эту древнюю тему. Насколько я понял, проблема в том что

КД>- один поток юзает ресурс
КД>- второй поток пытается этот ресурс убить
КД>- .NET второму потоку не позволяет такое делать

КД>Ну дык, полагаю, .NET тут прав на все 100%. И здесь нужно менять принцип прерывания работы с этим ресурсом. Или нет?


Без SafeHandle всё отлично прерывается и работает. Библиотека, которая отдаёт хэндл, сторонняя, так поменять API не представляется возможным. Я просто хотел сделать работу с unmanaged ресурсами "правильно", то есть через SafeHandle, ан нет, не получилось.
Ы?
Re[3]: SafeHandle и блокирующие операции
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 06.06.11 09:38
Оценка:
Здравствуйте, Igor Vyatkin, Вы писали:

КД>>Извините, что поднимаю эту древнюю тему. Насколько я понял, проблема в том что

КД>>- один поток юзает ресурс
КД>>- второй поток пытается этот ресурс убить
КД>>- .NET второму потоку не позволяет такое делать

КД>>Ну дык, полагаю, .NET тут прав на все 100%. И здесь нужно менять принцип прерывания работы с этим ресурсом. Или нет?


IV>Без SafeHandle всё отлично прерывается и работает. Библиотека, которая отдаёт хэндл, сторонняя, так поменять API не представляется возможным. Я просто хотел сделать работу с unmanaged ресурсами "правильно", то есть через SafeHandle, ан нет, не получилось.


И никаких падений/утечек ресурсов?

Получается что апишная функция закрытия ресурса прерывает работу другой апишной функции? Вообще — толковая идея
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[4]: SafeHandle и блокирующие операции
От: Igor Vyatkin  
Дата: 06.06.11 09:49
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Здравствуйте, Igor Vyatkin, Вы писали:


КД>>>Извините, что поднимаю эту древнюю тему. Насколько я понял, проблема в том что

КД>>>- один поток юзает ресурс
КД>>>- второй поток пытается этот ресурс убить
КД>>>- .NET второму потоку не позволяет такое делать

КД>>>Ну дык, полагаю, .NET тут прав на все 100%. И здесь нужно менять принцип прерывания работы с этим ресурсом. Или нет?


IV>>Без SafeHandle всё отлично прерывается и работает. Библиотека, которая отдаёт хэндл, сторонняя, так поменять API не представляется возможным. Я просто хотел сделать работу с unmanaged ресурсами "правильно", то есть через SafeHandle, ан нет, не получилось.


КД>И никаких падений/утечек ресурсов?


КД>Получается что апишная функция закрытия ресурса прерывает работу другой апишной функции? Вообще — толковая идея


К сожалению, асинхронного API у библиотеки нет, так что приходится извращаться. Библиотека отдаёт некий внутренний хэндл сервиса. Затем мы стартуем блокирующую функцию ожидания приёма данных. В моём случае, к сожалению, прервать эту функцию можно, только вызовом закрытия хэндла сервиса или закрытием приложения. Последнее меня не устраивает, так как мне нужно стартовать/стопать сервисы в рамках одного приложения динамически. Вот и приходится извращаться.
Ы?
Re[5]: SafeHandle и блокирующие операции
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 06.06.11 09:54
Оценка:
Здравствуйте, Igor Vyatkin, Вы писали:

IV>К сожалению, асинхронного API у библиотеки нет, так что приходится извращаться. Библиотека отдаёт некий внутренний хэндл сервиса. Затем мы стартуем блокирующую функцию ожидания приёма данных. В моём случае, к сожалению, прервать эту функцию можно, только вызовом закрытия хэндла сервиса или закрытием приложения. Последнее меня не устраивает, так как мне нужно стартовать/стопать сервисы в рамках одного приложения динамически. Вот и приходится извращаться.


Медицинское ПО, говоришь? Нафиг, нафиг
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.